考虑有状态小部件的状态类中的以下类级属性:
int myInt = widget.int;
Android Studio 通知:"无法在初始值设定项中访问实例成员'小部件'。
(我明白这个错误意味着什么)。
因此,如果我们添加 late 关键字,它似乎很好:
late int myInt = widget.int;
然而。。。这让我感到惊讶的是,我被允许在一行中完成所有这些操作——我认为后期变量不必设置为空:
late int myInt;
。然后在 onInit 内部分配。
由于我没有声明何时分配它,因此我不知道何时进行分配。
问题是:
单行"late int myInt = widget.int;"是否完全等同于在 initState 方法中自己分配它?
Dart 中的late
关键字有 2 种不同的用法,融合成一个关键字。
第一次使用,例如late int i
:
这种用法是众所周知的:延迟分配值,直到以后。这最常用于使字段不可为空,即使您可能没有立即获得该值。我相信你熟悉这种用法。
第二种用法,例如late int i = 0
:
这是为了延迟值计算,直到访问字段。当计算值的成本很高时,这很有用,因此您可能希望将其计算延迟到第一次需要它。官方文档中有说明:
执行此操作时,初始值设定项将变为延迟。而不是运行它 一旦实例被构造,它就会延迟并延迟运行 首次访问字段时。换句话说,它完全有效 就像顶级变量或静态字段上的初始值设定项一样。这可以 当初始化表达式成本高昂且可能不高时,请方便 需要。
所以基本上,取决于你是否立即分配一个值(在同一行上),Dart将决定你正在使用2种用法中的哪一种。如果你写late int i
这将是第一次用法,如果你写late int i = 0
或late int i = calculateValue()
这将是第二次用法:将计算延迟到第一次访问字段i
。这就像 Kotlin 中的lateinit
或 Swift 中的lazy
。
现在回到你的案例。通过在与late
关键字相同的行上分配值,您将使用第二种用法,基本上是"lazy init",直到第一次访问该字段。在访问它时,此类将被实例化,因此(到那时)您可以使用this
关键字。
在第一种情况下,Android studio会抛出该错误,因为int myInt
声明时需要一个值。
在那个特定时刻,在 Statefull 小组件状态下,widget
对象不可访问。
在第二种情况下:
late int myInt = widget.int;
这是变量的有效单行声明和赋值,但效果与onInit
替代方案略有不同。
late关键字的工作方式lazy
。 它不是在构建实例后立即运行,而是在第一次使用字段时运行。在那一刻,widget
对象将可以访问。
看看这个问题的答案,它会有所帮助:这里
在onInit
内分配值可保证在初始化小部件时实际上只分配一次该值。
widget.xxx
对应于小部件实例的xxx的值,即小部件一旦存在。
因此,当您在小部件初始化中使用widget.xxx
时,varxxx
不存在。
这就是为什么飞镖编译器告诉你The instance member 'widget' can't be accessed in an initializer
.
通过在声明前面添加关键字,可以告诉编译器稍后将定义此变量。
但要小心,它实际上必须在以后定义(例如在 initState 中),并且在任何情况下都不需要在使用之前。
此错误来自这样一个事实,即 dart 现在是一种空安全感知语言。
也就是说,一种努力确保没有变量可以具有空值的语言。这是出于代码质量和更高的代码安全性的原因。