如何修复 "The operator ‘{0}’ can’t be unconditionally invoked because the receiver can be ‘null’"
How to fix "The operator ‘{0}’ can’t be unconditionally invoked because the receiver can be ‘null’"
在尝试 Dart 的 Sound Null Safety 时,我遇到了一个问题:
一些上下文
创建一个新的 Flutter 项目我发现了以下(非常熟悉的)片段代码
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
现在,我将变量 _counter
更改为 nullable 并取消了初始化:
int? _counter;
void _incrementCounter() {
setState(() {
_counter++;
});
}
正如预期的那样,我在编辑器中收到以下错误:
The operator ‘+’ can’t be unconditionally invoked because the receiver can be 'null'
问题
在 the documentation 之后,我添加了所需的检查:
if (_counter!=null)
_counter++;
但令我惊讶的是,错误一直在显示和提示
Try making the call conditional (using '?' or adding a null check to the target ('!'))
即使我明确地有条件地进行调用...所以有什么问题吗?
更新
正如 , in a further thread in Github 中的建议,Erik Ernst 说:
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. 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.
所以,有了这个解释,现在我看到只有局部变量可以(到目前为止?)是 promoted,因此我的问题可以通过写
来解决
int? _counter;
void _incrementCounter() {
setState(() {
if (_counter!=null)
_counter = _counter! + 1;
});
}
对于替代修复,请参阅下面我的原始答案。
其他修正
我终于通过捕获方法内部实例变量的值解决了这个问题,如下所示:
int? _counter;
void _incrementCounter() {
setState(() {
var c = _counter;
if (c!=null)
c++;
_counter = c;
});
}
为什么需要捕获变量?
嗯,整个问题是
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
所以在我的方法中我们
- 捕获实例变量的值
- 然后我们检查 that value 是否为空。
- 如果结果证明该值不为空,那么我们将对通过空检查正确提升的局部变量进行操作。
- 最后我们将新值应用到实例变量。
最终观察
我是 Dart 的新手,因此我不是 100% 确定,但对我来说似乎 一般 ,在工作时对于可为空的实例变量,我的方法比使用 bang 运算符 cast away nullity:
更好
通过放弃无效性,您忽略了提升实例变量的主要问题,即
it could be overridden by a getter that runs a computation and returns a different object each time it is invoked ...
通过 捕获 实例变量的值并使用 that 本地捕获的值可以避免这个问题...
如果我错了请告诉我...
在尝试 Dart 的 Sound Null Safety 时,我遇到了一个问题:
一些上下文
创建一个新的 Flutter 项目我发现了以下(非常熟悉的)片段代码
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
现在,我将变量 _counter
更改为 nullable 并取消了初始化:
int? _counter;
void _incrementCounter() {
setState(() {
_counter++;
});
}
正如预期的那样,我在编辑器中收到以下错误:
The operator ‘+’ can’t be unconditionally invoked because the receiver can be 'null'
问题
在 the documentation 之后,我添加了所需的检查:
if (_counter!=null)
_counter++;
但令我惊讶的是,错误一直在显示和提示
Try making the call conditional (using '?' or adding a null check to the target ('!'))
即使我明确地有条件地进行调用...所以有什么问题吗?
更新
正如
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. 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.
所以,有了这个解释,现在我看到只有局部变量可以(到目前为止?)是 promoted,因此我的问题可以通过写
来解决int? _counter;
void _incrementCounter() {
setState(() {
if (_counter!=null)
_counter = _counter! + 1;
});
}
对于替代修复,请参阅下面我的原始答案。
其他修正
我终于通过捕获方法内部实例变量的值解决了这个问题,如下所示:
int? _counter;
void _incrementCounter() {
setState(() {
var c = _counter;
if (c!=null)
c++;
_counter = c;
});
}
为什么需要捕获变量?
嗯,整个问题是
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
所以在我的方法中我们
- 捕获实例变量的值
- 然后我们检查 that value 是否为空。
- 如果结果证明该值不为空,那么我们将对通过空检查正确提升的局部变量进行操作。
- 最后我们将新值应用到实例变量。
最终观察
我是 Dart 的新手,因此我不是 100% 确定,但对我来说似乎 一般 ,在工作时对于可为空的实例变量,我的方法比使用 bang 运算符 cast away nullity:
更好通过放弃无效性,您忽略了提升实例变量的主要问题,即
it could be overridden by a getter that runs a computation and returns a different object each time it is invoked ...
通过 捕获 实例变量的值并使用 that 本地捕获的值可以避免这个问题...
如果我错了请告诉我...