[英]"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety
I'm upgrading a personal package that is based on the Flutter framework.我正在升级基于 Flutter 框架的个人 package。 I noticed here in the Flutter Text widget source code that there is a null check:
我在 Flutter 文本小部件源代码中注意到这里有一个 null 检查:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan!
但是,
textSpan!
is still using the !
还在用
!
operator.操作员。 Shouldn't
textSpan
be promoted to a non-nullable type without having to use the !
不应该将
textSpan
提升为不可为空的类型而不必使用!
operator?操作员? However, trying to remove the operator gives the following error:
但是,尝试删除运算符会出现以下错误:
An expression whose value can be 'null' must be null-checked before it can be dereferenced. Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:这是一个独立的示例:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:我得到一个编译时错误:
Error: A value of type 'String?'
错误:“字符串?”类型的值can't be returned from function 'myString' because it has a return type of 'String'.
无法从 function 'myString' 返回,因为它的返回类型为 'String'。
Or if I try to get _mySting.length
I get the following error:或者,如果我尝试获取
_mySting.length
,则会收到以下错误:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
不能无条件访问属性“长度”,因为接收者可以为“空”。
I thought doing the null check would promote _myString
to a non-nullable type.我认为执行 null 检查会将
_myString
提升为不可为空的类型。 Why doesn't it?为什么不呢?
My question was solved on GitHub so I'm posting an answer below.我的问题在 GitHub 上得到了解决,所以我在下面发布了一个答案。
Dart engineer Erik Ernst says on GitHub : Dart 工程师 Erik Ernst 在 GitHub 上说:
Type promotion is only applicable to local variables.
类型提升仅适用于局部变量。 ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked.
...实例变量的提升并不合理,因为它可能被运行计算并在每次调用它时返回不同的 object 的 getter 覆盖。 Cf.
参照。 dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
dart-lang/language#1188用于讨论类似于类型提升但基于动态检查的机制,并提供一些相关讨论的链接。
So local type promotion works:所以本地类型推广有效:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote.但是实例变量不会提升。 For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the
!
为此,您需要使用
!
operator:操作员:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:假设这是您的代码,您正在对实例变量进行 null 检查,但仍然看到错误:
class Foo {
int? i = 0;
double func() {
if (i != null) return i.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
不能无条件地调用方法“toDouble”,因为接收者可以为“null”。
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts .您在这样的代码中看到的错误是因为Getter 没有提升为它们的不可为空的对应物。 Let's talk about the reason why.
让我们谈谈其中的原因。
Let's say, there's a class Bar
which extends Foo
and override i
variable and doesn't assign it any value (keeping it null
):假设,有一个 class
Bar
扩展Foo
并覆盖i
变量并且不为其分配任何值(保留它null
):
class Bar extends Foo {
@override
int? i;
}
So, if you could do所以,如果你能做到
print(Bar().func() * 2);
You would have run into a runtime null error, which is why getters type promotion is prohibited.您会遇到运行时 null 错误,这就是禁止 getter 类型提升的原因。
We need to cast away nullability from int?
我们需要抛弃
int?
. . There are generally 3 ways to do this (more ways include the use of
as
, is
, etc)通常有 3 种方法可以做到这一点(更多方法包括使用
as
、 is
等)
Use local variable (Recommended)使用局部变量(推荐)
double bar() { var i = this.i; // <-- Use of local variable. if (i.= null) return i;toDouble(); return -1; }
Use?.利用?。 with??
和??
double bar() { return i?.toDouble()?? -1; // Provide some default value. }
Use Bang operator (!)使用 Bang 运算符 (!)
You should only use this solution when you're 100% sure that the variable ( i
) will never be null
.只有当您 100% 确定变量 (
i
) 永远不会是null
时,才应该使用此解决方案。
double bar() { return i.;toDouble(). // <-- Bang operator in play. }
Use Ternary Operator to fix errors like this.使用三元运算符来修复这样的错误。 This is an example where headline1 can be null
这是一个示例,其中标题 1 可以是 null
Theme
.of(context)
.textTheme
.headline1?.fontSize?? 32,
style: Theme.of(context).textTheme.headline5..copyWith(风格: Theme.of(context).textTheme.headline5..copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using?尝试使用? or a null safety checker - !
或 null 安全检查器 - !
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.