该错误表明您正在尝试传递具有可为空类型的变量(SomeType?
) 作为函数的参数,该函数需要non-可为空的参数(SomeType
).
您必须检查该变量不是null
first.根据定义,可空类型可能具有以下值null
。将其传递给不期望的函数null
显然会很糟糕。先检查一下。例如:
import 'dart:math';
final random = Random();
class Foo {}
/// Randomly returns a [Foo] instance or `null`.
Foo? maybeGetFoo() => random.nextBool() ? Foo() : null;
void printFoo(Foo fooInstance) => print(fooInstance);
void main() {
Foo? foo = maybeGetFoo();
printFoo(foo); // ERROR: The argument type 'Foo?' can't be assigned to the parameter type 'Foo'
if (foo != null) {
printFoo(foo); // OK, `foo` is now provably known to be of type `Foo`.
}
}
通过检查是否local foo
变量是null
, foo
可以自动类型提升为不可空类型。
请注意,自动类型升级只能发生在local变量或者例如变量都是final和私人的。:
class Bar {
Foo? foo;
Bar(this.foo);
void printMember() {
if (foo != null) {
printFoo(foo); // ERROR
}
}
}
要解决此问题,您必须使用中间局部变量(首选):
void printMember() {
// Shadow with a local variable to allow automatic type promotion to occur.
final foo = this.foo;
if (foo != null) {
printFoo(foo); // OK, `foo` is now provably known to be of type `Foo`.
}
}
或者你必须显式强制转换为不可空类型:
void printMember() {
if (foo != null) {
printFoo(foo!); // Compiles.
printFoo(foo as Foo); // Compiles.
}
}
使用显式强制转换(无论是!
或与as
)通常应该是最后的手段。重要的是,只有当您已经确定该值不是时才使用它null
;如果是null
, then !
and as
会抛出一个TypeError
在运行时并且应该使你的程序崩溃。此外,出于同样的原因,非局部变量不会自动进行类型提升,使用显式强制转换不一定安全,尽管实际上对于非病态代码来说通常应该没问题。
另请注意,在一些不常见的情况下,即使是局部变量在检查后也可能仍可为空(例如,变量在检查后重新分配)。看https://dart.dev/tools/non-promotion-reasons.
I also strongly推荐阅读 Dart 的了解零安全性文章。
最后,这并不是真正特定于空安全的;转换自Foo?
to Foo
只是一种形式downcast、和(后缀除外!
运算符),以上所有内容通常适用于向下转型。从基本类型(例如从Object
or dynamic
) 到派生类型也只会发生在局部变量或final
,私有实例变量:
class Baz {
Object maybeFoo;
Baz(this.maybeFoo);
}
void main() {
var baz = Baz(Foo());
if (baz.maybeFoo is Foo) {
printFoo(baz.maybeFoo); // ERROR
printFoo(baz.maybeFoo as Foo); // Compiles.
}
final maybeFoo = baz.maybeFoo;
if (maybeFoo is Foo) {
printFoo(maybeFoo); // OK, `maybeFoo` is now provably known to be of type `Foo`.
}
}