健全的空安全 null safety 让你对代码中的 null 可见且可控,并且确保它不会传递至某些位置从而引发崩溃 runtime errors into edit-time analysis errors
Dart basics | Dart https://dart.dev/language
Important concepts
As you continue to learn about the Dart language, keep these facts and concepts in mind:
-
Everything you can place in a variable is an object, and every object is an instance of a class. Even numbers, functions, and
null
are objects. With the exception ofnull
(if you enable sound null safety), all objects inherit from theObject
class.Version note: Null safety was introduced in Dart 2.12. Using null safety requires a language version of at least 2.12.
-
Although Dart is strongly typed, type annotations are optional because Dart can infer types. In
var number = 101
,number
is inferred to be of typeint
. -
If you enable null safety, variables can’t contain
null
unless you say they can. You can make a variable nullable by putting a question mark (?
) at the end of its type. For example, a variable of typeint?
might be an integer, or it might benull
. If you know that an expression never evaluates tonull
but Dart disagrees, you can add!
to assert that it isn’t null (and to throw an exception if it is). An example:int x = nullableButNotNullInt!
Sound null safety | Dart https://dart.dev/null-safety
Sound null safety
The Dart language enforces sound null safety.
Null safety prevents errors that result from unintentional access of variables set to null
.
For example, if a method expects an integer but receives null
, your app causes a runtime error. This type of error, a null dereference error, can be difficult to debug.
With sound null safety, all variables require a value. This means Dart considers all variables non-nullable. You can assign values of the declared type only, like int i=42
. You can never assign a value of null
to default variable types. To specify that a variable type can have a null
value, add a ?
after the type annotation: int? i
. These specific types can contain either a null
or a value of the defined type.
Sound null safety changes potential runtime errors into edit-time analysis errors. With null safety, the Dart analyzer and compilers flag if a non-nullable variable has either:
- Not been initialized with a non-null value
- Been assigned a
null
value. These checks allows you to fix these errors before deploying your app.
Introduction through examples
With null safety, none of the variables in the following code can be null
:
// With null safety, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
To indicate that a variable might have the value null
, just add ?
to its type declaration:
int? aNullableInt = null;
- To try an interactive example, see the null safety codelab.
- To learn more about this topic, see Understanding null safety.
Null safety principles
Dart supports null safety using the following three core design principles:
-
Non-nullable by default. Unless you explicitly tell Dart that a variable can be null, it’s considered non-nullable. This default was chosen after research found that non-null was by far the most common choice in APIs.
-
Fully sound. Dart’s null safety is sound, which enables compiler optimizations. If the type system determines that something isn’t null, then that thing can never be null. Once you migrate your whole project and its dependencies to null safety, you reap the full benefits of soundness—not only fewer bugs, but smaller binaries and faster execution.
健全的空安全 | Dart https://dart.cn/null-safety
健全的空安全
The Dart language comes with sound null safety.
Dart 语言包含了健全的空安全特性。
空安全会在编译期防止意外访问 null
变量的错误的产生。例如,如果一个方法需要整型结果,却接收到了 null
,你的应用会出现运行时错误。这类空引用错误在以前调试是非常困难的。
有了健全的空安全体系,变量默认是「非空」的:它们可以赋予与定义的类型相同类型的任意值(例如 int i = 42
),且永远不能被设置为 null
。你可以指定一个类型为可空(例如 int? i
),这类变量只能包含对应类型的值或者 null
。
健全的空安全通过对非空变量的未被初始化或以 null
初始化的情况进行标记,把潜在的 运行时错误 转变成了 编辑时 的分析错误。这样的特性让你在开发应用的过程中就可以修复这类错误。
通过示例代码介绍空安全
有了空安全,下面代码中所有的变量都是非空的:
// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
int? aNullableInt = null;
-
你可以通过 空安全 Codelab 交互示例快速了解空安全。
-
更深入的探讨,可以阅读文档 深入理解空安全。
空安全的原则
Dart 的空安全支持基于以下三条核心原则:
-
默认不可空。除非你将变量显式声明为可空,否则它一定是非空的类型。我们在研究后发现,非空是目前的 API 中最常见的选择,所以选择了非空作为默认值。
-
渐进迁移。你可以自由地选择何时进行迁移,多少代码会进行迁移。你可以使用混合模式的空安全,在一个项目中同时使用空安全和非空安全的代码。我们也提供了帮助你进行迁移的工具。
-
完全可靠。Dart 的空安全是非常可靠的,意味着编译期间包含了很多优化。如果类型系统推断出某个变量不为空,那么它 永远 不为空。当你将整个项目和其依赖完全迁移至空安全后,你会享有健全性带来的所有优势—— 更少的 BUG、更小的二进制文件以及更快的执行速度。
空安全常见问题 | Dart https://dart.cn/null-safety/faq
深入理解空安全 | Dart https://dart.cn/null-safety/understanding-null-safety
总结
这是一场非常详尽的空安全旅途,途中走遍了所有语言和库的变更。这其中的内容真的很多,但是这也是一项非常大的语言变更。更重要的是,我们希望 Dart 仍然让你感到好用且具备一致性。所以不仅类型系统需要作出变动,一些可用性的特性也同时围绕着一起改变。我们不希望空安全仅仅是一个简陋的语法附加特性。
你需要掌握的核心要点有:
-
类型默认是非空的,可以添加
?
变为可空的。 -
可选参数必须是可空的或者包含默认值的。你可以使用
required
来构建一个非可选命名参数。非空的全局变量和静态字段必须在声明时被初始化。实例的非空字段必须在构造体开始执行前被初始化。 -
如果接收者为
null
,那么在其避空运算符之后的链式方法调用都会被截断。我们引入了新的空判断级联操作符 (?..
) 及索引操作符 (?[]
)。后缀空断言“重点”操作符 (!
) 可以将可空的操作对象转换为对应的非空类型。 -
新的流程分析,让你更安全地将可空的局部变量和参数,转变为可用的非空类型。它同时还对类型提升、遗漏的返回、不可达的代码以及变量的初始化,有着更为智能的规则。
-
late
修饰符以在运行时每次都进行检查的高昂代价,让你在一些原本无法使用的地方,能够使用非空类型和final
。它同时提供了对字段延迟初始化的支持。 -
List
类现在不再允许包含未初始化的元素。
最后,当你掌握了这篇文章的所有内容,并且将你的代码真正带到空安全的世界中时,你会得到一个健全的、编译器可以进行优化的程序,并且在你的代码中,你可以看到每一个运行时可能出错的地方。希望你的一切努力都是值得的。