封面图
用ts定义了一些类,用来实现前端监控系统。
Dart类型系统
Dart使用了静态类型检查
和运行时检查
组合,用于确保变量的类型始终保持一定的正确性。虽然Dart是强类型语言,但是由于存在类型推断
,所以在声明变量时,也不一定非得指定变量的类型,类型推断
会自动推断变量的类型。
ps: 这一点和和ts非常相似。
静态类型检查的一个好处是能够让Dart的静态分析器(static analyzer)
在编译时发现相应的错误。
我们可以通过向泛型类添加类型注释来修复大多数静态分析错误。最常见的泛型类是集合类型List<T>
和Map<K,V>
。
比如:下面的例子中printInts()
方法打印的是一个int类型的数值列表,main()
方法创建了一个列表,传给printInts()
进行打印:
void printInts(List<int> a) => print(a);
void main() {
final list = [];
list.add(1);
list.add('2');
printInts(list); // static analysis : error /warning
}
这时候会出现一个类型错误的报错。
error - The argument type 'List<dynamic>' can't be assigned to the parameter type 'List<int>'. - argument_type_not_assignable
dynamic
类型不能赋值给int
类型。
其实这是因为中间存在一个隐式转换
。
list
在初始化时没有指定类型,因而分析器
没有足够的信息来推断比dynamic
类型更合适的类型,但是打印方法需要int
类型才能正确执行,因而导致类型的不匹配。
当我们给list
指定int
类型后,同时向list中添加正确的数值,则可以避免这个问题。
void printInts(List<int> a) => print(a);
void main() {
final list = <int>[];
list.add(1);
list.add(2);
printInts(list); // success
}
Soundness 完整性? 强制性?健全性?强类型语言?
我们都知道TS是一种强类型语言,也知道它也有静态检查和运行时检查,可以帮助我们在代码编译时发现代码中的错误。
但是,有这种检查的功能就是强类型语言吗?这种理解也许稍微有点牵强,不够深刻。
强类型,健全性表现在它可以确保我们的程序不会进入到某种无效的状态。这种无效状态指的是表达式计算值
与表达式静态类型
不匹配的状态。比如:假如我们的表达式静态类型是string
,那么在代码运行的时候,我们可以保证计算这个字符串时变量获得的必然是字符串。
强类型的好处
强类型的优点我们都知道:
- 可以在编译时提示与类型相关的错误信息,避免运行时出现错误。
- 可以提高代码的可读性,其他成员可以很方便的获取代码的相关信息,不用来会翻代码来猜测某些对象中有哪些属性。
- 可读性好,那么代码的可维护性必然会提高很多。
- 更好的预(AOT)编译。虽然AOT编译在没有类型的情况下是可能的,但生成的代码效率要低得多。
类型推断
类型推断
这个词我们都知道,也知道TS中也存在类型推断,但是类型推断的过程是什么?很少有人能说明白。
在Dart中,分析器(analyzer)
可以推断字段、方法、局部变量和大多数泛型类型参数的类型。当分析器没有足够的信息来推断特定的类型时,它会使用动态类型dynamic type
。
比如:我们定义一个名为arguments
的变量,它是一个map类型。
Map<String, dynamic> arguments = {'argA': 'hello', 'argB': 42};
当然我们也用var
定义这个变量,然后Darth会对类型进行推断:
var arguments = {'argA': 'hello', 'argB': 42}; // Map<String, Object>
Map会推断它的每个条目argA,argB
,然后根据条目去推断它们对应的类型。
比如上面的map中,map的键argA,argB
都是字符串,但是它们的值一个是string
,一个是int
,但是它们的上层对象都是Object
,所以整体会被推断为Map<String, Object>
。
字段,属性,方法的推断
没有指定类型并且从父类中重写的字段或方法,或者方法继承自父类的方法或字段的类型,这些类型会继承父类中对应的类型。
没有指定类型或者没有使用继承的变量,但是进行了初始化,这种类型推断会根据初始值进行。
比如:
var a = 'hello world'
初始值是字符串,则后面会推断为string
类型。
即,推断变量的类型取决于知道该变量的类型
。
局部变量推断
局部变量推断也是根据变量的初始值进行推断,并且不考虑后续的赋值操作。比如:
var x = 3; // x is inferred as an int.
x = 4.0; // static analysis: error /warning
x
根据其初始值被推断为int
类型,后面赋值为double
类型,则会提示错误。
当我们初始化时指定其类型后则不会报错:
num y = 3; // A num can be double or int.
y = 4.0; // success
最后
先写到这里。
简单理解一下强类型语言的稍微深刻一点的认识,同时简单理解一下类型推断
到底是怎么进行的推断。
文笔有限,多谢~
公众号《Javascript高级程序设计》,文章会同步到公众号。