Dart从2.12开始,支持健全的空安全机制。
在Dart、Flutter中开启空安全后,代码中所有的类型默认都会是非空类型的,它们的值都不能为空,也就是代码中的null
。除非使用?
声明为可空。
有了空安全,原本处于运行时
的空值引用错误将变为编译时
的分析错误,这样的好处是将程序运行时才会出现的空指针异常提供在编译基暴露出来。
为了方便理解,我先定义一个class
class Person { Children children; work() { print("人在工作"); } toString() { return "这是一个人"; } } class Children { eat() { print("孩子吃饭啦"); } }
声明可空类型
在声明变量的类型后加上?
操作符,就代表变量是可空的。
void main() { Person? p; }
避空操作符?
如果我们无法知道某个可空变量在运行时是否为空,但是我们需要调用变量的方法或属性,为了代码的健壮性,我们可以使用?
操作符。
Person? p; p.work();
像这样写后,dart编译器会直接给出错误提示,因为被调用方法的对象可能为null。
我们只需要在调用时加上?
来避免空操作。
void main() { Person? p; /// 跳过运行 p.work(); print("程序结束"); }
打印结果: 程序结束。
因为p是一个Null对象,所以p.work()
不会运行,直接跳过。
空值断言操作符!
空安全下,以下代码会在error.toUpperCase()
一个编译错误。
class HttpResponse { final int code; final String? error; HttpResponse.ok() : code = 200, error = null; HttpResponse.notFound() : code = 404, error = 'Not found'; @override String toString() { if (code == 200) return 'OK'; return 'ERROR $code ${error.toUpperCase()}'; } }
但是我们人为地可以观察出,在code不等于200的时候,error是肯定不为null的,但是编译器并不知道code和error之间的联系。
这时候空值断言操作符!
就能派上用场了。
一个作为后缀的感叹号标记 (!) 会让左侧的表达式转换成其对应的非空类型。
String toString() { if (code == 200) return 'OK'; return 'ERROR $code ${error!.toUpperCase()}'; }
加上!
会告诉编译器,在!
的左侧的变量肯定是不为空的,这样就可以正常通过编译了。