0
点赞
收藏
分享

微信扫一扫

第131期:Dart类型和类型推断

封面图

第131期:Dart类型和类型推断_强类型

用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高级程序设计》,文章会同步到公众号。

举报

相关推荐

0 条评论