三个运算符总览(as /is/is!)
| 运算符 | 作用说明 |
|---|---|
as | 类型强制转换;也可用于库前缀限定 |
is | 类型判断:对象属于指定类型返回 true |
is! | 类型判断:对象不属于指定类型返回 true |
obj is T 判断成立条件:对象 obj 实现 / 继承了类型 T(包含父类、接口、可空类型)。
例如 任意对象 is Object? 永远为 true。
is 运算符
安全类型判断
判断对象运行时类型; 如果是true,代码块内可以直接认为是这种类型来使用就可以,不用手动强转; 对象为 null 或类型不匹配时,直接返回 false,不会抛异常。
例如下面用到类对象,读者可能还没学到类,可以暂且理解它为一个用来构造数据的模型就可以。
class Person {
String firstName = '';
}
class Employee extends Person {}
void main() {
dynamic employee = Employee();
// 使用 is 判断类型
if (employee is Person) {
// 进入分支后,employee 自动识别为 Person 类型
employee.firstName = "Jack";
print(employee.firstName); // 输出 Jack
}
dynamic emptyObj = null;
if (emptyObj is Person) {
// 不会执行,null 不匹配 Person
print("匹配成功");
}
}Code language: Dart (dart)
以上代码 定义了一个Person类 然后再定义一个雇员类,雇员类继承了Persion类。
在代码中,用is来判断一个对象是否是Person,如果是,在代码块{} 中可以直接当成Person来使用就可以。因为这个dynamic employee = Employee(); 用到了动态类型。
第二个例子中 dynamic emptyObj = null; 因为是null,所以emptyObj is Person是false,那么就不会执行{}里面的代码。
is! 运算符
反向类型判断
语法:
变量 is! 类型
其实等价于前面的is 然后取反。
等价于 !(变量 is 类型),判断对象不是目标类型。
看例子:
class Person {
String name = '';
}
void main() {
dynamic obj = "文本";
if (obj is! Person) {
print("obj 不是 Person 类型");
}
}Code language: Dart (dart)
以上例子 会执行{}代码块中的内容 输出“obj 不是 Person 类型”,因为obj 的确不是Person的对象(通过Person这个摸具创建出来的具体的一个实例)
as 运算符
强制类型转换
用法:
(变量 as 目标类型).属性/方法Code language: JavaScript (javascript)
读者如果百分百确定该对象就是目标类型,就可以使用,否则会抛出运行时异常。所以为了程序的健壮性,不建议大量使用。
class Teacher {
String name = '';
}
void main() {
dynamic jason = Teacher();
// 强制转为 Teacher 再访问属性
(jason as Teacher).name = "Jason";
print((jason as Teacher).name); // Jason
}Code language: Dart (dart)
以上例子输出Jason
因为我们是直接dynamic jason = Teacher(); 创建了一个Teacher的对象,所以我们可以百分比保证它是一个Teacher,所以这里可以这样用。不会报错。

如果我们这样写,就会出错了。
class Teacher {
String name = '';
}
class Car {
String name = '';
}
void main() {
dynamic jason = Teacher();
// 强制转为 Car 再访问属性
(jason as Car).name = "Jason";//❌错误
print((jason as Car).name); //❌错误
}Code language: Dart (dart)
因为jason本来是一个Teacher,但是下面强制转换为Car,这样是会错误的。
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'Teacher' is not a subtype of type 'Car' in type cast
#0 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:12:10)
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
as 和 is 核心对比
// 写法1:as 强制转换
(employee as Person).firstName = 'Bob';
// 写法2:is 先判断再使用
if (employee is Person) {
employee.firstName = 'Bob';
}Code language: JavaScript (javascript)
当 employee 是 null 或不是 Person:
as版本:直接抛出CastError程序崩溃;is版本:不进入 if 分支,代码无报错、无操作。
所以,优先使用is的方式,尽管需要写多一点代码,但是程序的健壮性更好。
as 的第二种用途
as 的第二种用途
as 不只是类型转换,导入库时可给库起别名
import 'dart:math' as math;
void main() {
// 通过库别名来调用类/方法
print(math.pi); //输出 3.141592653589793
}Code language: JavaScript (javascript)
最后,完整例子
class Animal {}
class Cat extends Animal {}
void main() {
dynamic obj = Cat();
// 1. is 判断
if (obj is Animal) {
print("obj 是 Animal");
}
// 2. is! 反向判断
if (obj is! String) {
print("obj 不是字符串");
}
// 3. as 强转
Animal a = obj as Animal;
// 4. 错误示范,会崩溃
dynamic str = "hello";
// Animal error = str as Animal; // CastError
}Code language: JavaScript (javascript)