Dart 类型测试运算符

三个运算符总览(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)

asis 核心对比

// 写法1:as 强制转换
(employee as Person).firstName = 'Bob';

// 写法2:is 先判断再使用
if (employee is Person) {
  employee.firstName = 'Bob';
}Code language: JavaScript (javascript)

employeenull 或不是 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)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注