Null安全性/非空(默认情况下),简称NNBD,目前可以在nullsafety.dartpad.dev找到。
请注意,您可以阅读此处的完整规范和此处的完整路线图。现在,Dart也已经官方宣布了声音的null安全性。点击这里查看。
void main() {
String word;
print(word); // illegal
word = 'Hello, ';
print(word); // legal
}
如上所示,默认情况下非空(non-nullable)的变量意味着每个通常声明的变量不能为null
。因此,在变量被赋值之前访问该变量的任何操作都是不合法的。
此外,将 null
赋值给非空变量也是不允许的:
void main() {
String word;
word = null; // forbidden
world = 'World!'; // allowed
}
如果一个变量是 非空 的,你可以确定它永远不会是 null
。因此,你无需事先检查它。
int number = 4;
void main() {
if (number == null) return; // redundant
int sum = number + 2; // allowed because number is also non-nullable
}
如果类中的实例字段是非空字段,必须初始化:
class Foo {
String word; // forbidden
String sentence = 'Hello, World!'; // allowed
}
请看下面的 late
来修改这种行为。
?
)您可以在变量类型后添加问号 ?
来使用可空类型:
class Foo {
String word; // forbidden
String? sentence; // allowed
}
可空变量在使用之前无需初始化,它会默认初始化为null
:
void main() {
String? word;
print(word); // prints null
}
!
将!
附加到任何变量e
上,如果e
为null,则会抛出运行时错误,否则将其转换为非空值v
。
void main() {
int? e = 5;
int v = e!; // v is non-nullable; would throw an error if e were null
String? word;
print(word!); // throws runtime error if word is null
print(null!); // throws runtime error
}
late
late
关键字可以用来标记那些在声明时不进行初始化,而是在被访问时才进行初始化的变量,即延迟初始化。这也意味着我们可以拥有非空的实例字段,并在稍后进行初始化:
class ExampleState extends State {
late final String word; // non-nullable
@override
void initState() {
super.initState();
// print(word) here would throw a runtime error
word = 'Hello';
}
}
在初始化之前访问word
会抛出运行时错误。
late final
现在,final变量也可以标记为late:
late final int x = heavyComputation();
只有当访问 x
时才会调用heavyComputation
。此外,您还可以声明一个没有初始化器的 late final
,这与仅有一个late
变量相同,但是它只能分配一次。
late final int x;
// w/e
x = 5; // allowed
x = 6; // forbidden
请注意,所有带有初始值的顶层或静态变量现在都将被评估为late
,无论它们是否是final
。
required
之前是一个注释(@required
),现在作为修饰符内置。它允许将任何命名参数(用于函数或类)标记为required
,这使它们不可为空:
void allowed({required String word}) => null;
这也意味着,如果参数应该是不可为空的,它需要被标记为required
或具有默认值:
void allowed({String word = 'World'}) => null;
void forbidden({int x}) // compile-time error because x can be null (unassigned)
=>
null;
任何其他的命名参数都必须可为空:
void baz({int? x}) => null;
?[]
针对索引操作符[]
添加了空安全的?[]
运算符:
void main() {
List<int>? list = [1, 2, 3];
int? x = list?[0]; // 1
}
另请参阅有关语法决策的文章。
?..
级联运算符现在也有了一个新的空安全运算符:?..
。如果接收方不为null,它会导致以下级联操作只执行一次。因此?..
必须是级联序列中的第一个级联运算符:
void main() {
Path? path;
// Will not do anything if path is null.
path
?..moveTo(3, 4)
..lineTo(4, 3);
// This is a noop.
(null as List)
?..add(4)
..add(2)
..add(0);
}
Never
下面的解释很差。请阅读“了解空安全性”中的“顶部和底部”以获取更好的解释。
为避免混淆:这不是开发人员需要担心的事情。我提及它是为了完整性的缘故。
Never
将成为像先前存在的 Null
(而不是 null
)一样的类型,定义在 dart:core
中。这两个类都不能被扩展、实现或混合,因此不打算使用它们。
本质上,Never
意味着不允许使用任何类型,且 Never
本身不能被实例化。
一个 List<Never>
中除了 Never
之外任何其他东西都无法满足列表的泛型约束,这意味着它必须为空。List<Null>
可以包含 null
:
// Only valid state: []
final neverList = <Never>[
// Any value but Never here will be an error.
5, // error
null, // error
Never, // not a value (compile-time error)
];
// Can contain null: [null]
final nullList = <Null>[
// Any value but Null will be an error.
5, // error
null, // allowed
Never, // not a value (compile-time error)
Null, // not a value (compile-time error)
];
示例:编译器将为一个空const List<T>
推断出List<Never>
。
就我所知,Never
不应该被程序员使用。(我错了)。
您可以阅读关于空安全的官方文章。
此外,如开头所述,您可以在DartPad上试试。
const phonefield({
Key? key, required this.onchanged,
}) : super(key: key);
final ValueChanged<String>onchanged;