Dart 健全类型安全(Sound Type System)
核心定义
Dart 属于健全静态类型语言,依靠「静态编译检查 + 运行时校验」双重保障:变量运行时的值一定和它静态声明类型匹配。
类型规则强制生效,但类型注解可省略,由类型推断自动推导;
编译期静态分析提前拦截绝大多数类型错误。
什么是健全性(Soundness)
代码不会进入非法类型状态;若表达式静态类型是 String,运行时一定只能拿到字符串,不会出现其他类型。 同类语言:Java、C#。
- 编译期拦截:
int a = "abc";直接报错; - 运行时拦截:使用
as强制转换类型不匹配时抛出异常。
四大优势
编译期暴露类型 bug,规避难复现的线上类型崩溃;
代码可读性更高,类型不会 “欺骗开发者”;
代码易维护,修改一处代码,类型检查提示所有受影响代码;
AOT 编译效率更高,类型信息帮助编译器生成更高效机器码。
例子
动态集合引发静态报错
// 预期接收 List<int>
void printInts(List<int> a) => print(a);
void main() {
// 无泛型声明,自动推断为 List<dynamic>
final list = [];
list.add(1);
list.add('2'); // 动态列表可混存类型
printInts(list);
// 编译报错:List<dynamic> 不能赋值给 List<int>
}Code language: Dart (dart)
显式声明泛型约束
void printInts(List<int> a) => print(a);
void main() {
final list = <int>[]; // 显式指定泛型int
list.add(1);
// list.add('2'); // 编译报错,无法放入字符串
list.add(2);
printInts(list); // 正常通过静态检查
}Code language: Dart (dart)
三大核心规则
1 重写方法时,返回类型必须是原类型或其子类型(生产者规则)
父类方法返回值是生产者,子类可以返回更具体的子类型,不能返回无关类型。
例如
正确示例
class Animal {
Animal get parent => Animal();
}
class HoneyBadger extends Animal {
@override
HoneyBadger get parent => HoneyBadger(); // 子类型,合法
}Code language: Dart (dart)
错误示例
class Root {}
class HoneyBadger extends Animal {
@override
Root get parent => Root(); // 无关类型,编译报错
}Code language: Dart (dart)
2 重写方法时,参数类型必须是原类型或其父类型
方法入参是消费者,子类只能放宽参数范围(父类型),不能缩小为子类型;缩小会破坏类型安全。
正确示例(参数放宽到 Object)
class Animal {
void chase(Animal a) {}
}
class HoneyBadger extends Animal {
@override
void chase(Object a) {} // Object是Animal父类,合法
}Code language: Dart (dart)
错误示例(参数缩小为子类 Mouse)
class Mouse extends Animal {}
class Cat extends Animal {
@override
void chase(Mouse a) {} // 缩小参数类型,静态报错
}
void main() {
Animal cat = Cat();
cat.chase(Alligator()); // 理论上允许传入Alligator,造成类型不安全
}Code language: Dart (dart)
规则 3:不能把动态泛型集合直接赋值给确定泛型集合
List<dynamic>、List<Dog> 无法直接赋值给 List<Cat>,编译报错;不同泛型集合不存在隐式转换。
class Cat {}
class Dog {}
void main() {
List<Cat> foo = <dynamic>[Dog()]; // 静态报错
List<dynamic> bar = <dynamic>[Dog(), Cat()]; // 合法,动态列表可混合类型
}Code language: Dart (dart)
运行时类型校验
静态检查无法覆盖全部场景,运行时会额外校验类型,不匹配抛出异常。
泛型强制转换运行时报错
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
void main() {
List<Animal> animals = <Dog>[Dog()];
List<Cat> cats = animals as List<Cat>;
// 运行时异常:无法将List<Dog>强转为List<Cat>
}Code language: Dart (dart)
dynamic 隐式向下转换(运行校验)
dynamic 变量赋值给具体类型会隐式转换,运行时校验类型,不匹配抛错。
int assumeString(dynamic object) {
String string = object; // 运行时校验object是否为String
return string.length;
}
void main() {
assumeString("test"); // 正常执行
assumeString(123); // 运行时报错:int不能转为String
}Code language: Dart (dart)
关闭隐式转换(严格类型模式)
在 analysis_options.yaml 开启严格转换,禁止 dynamic 隐式向下转
analyzer:
language:
strict-casts: trueCode language: JavaScript (javascript)
类型推断 Type Inference
Dart 自动推导变量、泛型、方法返回值类型;信息不足时默认推断为 dynamic。
普通变量推断
// 自动推导 Map<String, Object>
var arguments = {'argA': 'hello', 'argB': 42};
var x = 3; // x 推断为 int
x = 4.0; // 报错,int不能存double
num y = 3; // 显式声明num,可存int/double
y = 4.0; // 合法Code language: Dart (dart)
泛型构造 / 集合推断
List<int> listOfInt = []; // 自动推导 <int>[]
var listOfDouble = [3.0]; // 推导 List<double>
var ints = listOfDouble.map((x) => x.toInt());
// x推导为double,回调返回int,ints推导为Iterable<int>Code language: Dart (dart)