Dart 语言里的类型体系

19 阅读3分钟

Dart 是类型安全的编程语言:Dart 使用静态类型检查和 运行时检查 的组合来确保变量的值始终与变量的静态类型或其他安全类型相匹配。尽管类型是必需的,但由于 类型推断,类型的注释是可选的。

静态类型检查的一个好处是能够使用 Dart 的 静态分析器 在编译时找到错误。

可以向泛型类添加类型注释来修复大多数静态分析错误。最常见的泛型类是集合类型 List<T> 和 Map<K,V> 。

在下面的代码中,main() 创建一个列表并将其传递给 printInts(),由 printInts() 函数打印这个整数列表。

void printInts(List<int> a) => print(a);

void main() {
  final list = [];
  list.add(1);
  list.add('2');
  printInts(list);
}

上面的代码在调用 printInts(list) 时会在 list (高亮提示)上产生类型错误:

error - The argument type 'List<dynamic>' can't be assigned to the parameter type 'List<int>'. - argument_type_not_assignable

高亮错误是因为产生了从 List<dynamic> 到 List<int> 的不正确的隐式转换。 list 变量是 List<dynamic> 静态类型。这是因为 list 变量的初始化声明 var list = [] 没有为分析器提供足够的信息来推断比 dynamic 更具体的类型参数。 printInts() 函数需要 List<int> 类型的参数,因此导致类型不匹配。

在创建 list 时添加类型注释 <int>(代码中高亮显示部分)后,分析器会提示无法将字符串参数分配给 int 参数。删除 list.add("2") 中的字符串引号使代码通过静态分析并能够正常执行。

void printInts(List<int> a) => print(a);

void main() {
  final list = <int>[];
  list.add(1);
  list.add(2);
  printInts(list);
}

类型安全

类型安全是为了确保程序不会进入某些无效状态。安全的类型系统意味着程序永远不会进入表达式求值为与表达式的静态类型不匹配的值的状态。例如,如果表达式的静态类型是 String ,则在运行时保证在评估它的时候只会获取字符串。

Dart 的类型系统,同 Java 和 C#中的类型系统类似,是安全的。它使用静态检查(编译时错误)和运行时检查的组合来强制执行类型安全。例如,将 String 分配给 int 是一个编译时错误。如果对象不是字符串,使用 as String 将对象转换为字符串时,会由于运行时错误而导致转换失败。

类型安全的好处

安全的类型系统有以下几个好处:

  • 在编译时就可以检查并显示类型相关的错误。
    安全的类型系统强制要求代码明确类型,因此在编译时会显示与类型相关的错误,这些错误可能在运行时可能很难发现。
  • 代码更容易阅读。
    代码更容易阅读,因为我们信赖一个拥有指定类型的值。在类型安全的 Dart 中,类型是不会骗人的。因为一个拥有指定类型的值是可以被信赖的。
  • 代码可维护性更高。
    在安全的类型系统下,当更改一处代码后,类型系统会警告因此影响到的其他代码块。
  • 更好的 AOT 编译。
    虽然在没有类型的情况下可以进行 AOT 编译,但生成的代码效率要低很多。

静态检查中的一些技巧

大多数静态类型的规则都很容易理解。下面是一些不太明显的规则:

  • 重写方法时,使用类型安全返回值。
  • 重写方法时,使用类型安全的参数。
  • 不要将动态类型的 List 看做是有类型的 List。