Flutter:在有状态 Widget 中延迟初始化 "widget-dot" Class 级变量——这是怎么回事?

Flutter: Late Initializing a "widget-dot" Class-level Variable in a Stateful Widget -- What's Going on?

考虑有状态小部件的状态 class 内的以下 class 级别 属性:

int myInt = widget.int;

Android Studio 通知:“无法在初始化程序中访问实例成员 'widget'。”

(我明白这个错误是什么意思)。

那么如果我们添加 late 关键字,看起来就没问题了:

late int myInt = widget.int;

然而...令我惊讶的是,我被允许在一行中完成所有这些——我认为晚期变量必须不是 set/set as null:

late int myInt;

...然后在onInit里面赋值。

因为我没有声明什么时候赋值,所以不知道什么时候赋值。

问题是:

就是一行“late int myInt = widget.int;”完全等同于自己在initState方法中赋值?

widget.xxx对应widget实例的xxx的值,即widget一旦存在

因此,当您在小部件的初始化中使用 widget.xxx 时,var xxx 不存在。

这就是为什么 dart 编译器会告诉你 The instance member 'widget' can't be accessed in an initializer

通过在声明前添加关键字 late,您告诉编译器该变量将在稍后定义。

但是要小心,它真的必须稍后定义(例如在 initState 中)并且在任何情况下都必须在使用之前定义。

此错误是由于 dart 现在是一种空的安全意识语言。

也就是说,一种语言努力确保没有变量可以有空值。这是出于代码质量和更高代码安全性的原因。

在第一种情况下 Android studio 会抛出该错误,因为 int myInt 在您声明它时需要一个值。

在那个特定时刻,在 Statefull 小部件状态下,widget 对象不可访问。

第二种情况:

late int myInt = widget.int;

这是有效的一行声明和变量赋值,但效果与 onInit 替代方案有点不同。

late 关键字以 lazy 方式工作。 不是在构建实例后立即 运行ning,而是在第一次使用该字段时 运行。在那一刻,widget 对象将可以访问。

看看这个问题的答案,可能会有帮助:

onInit 中赋值可以保证在初始化小部件时实际上只赋值一次。

Dart中的late关键字有2种不同的用法,融为一个关键字。


第一个用法,例如late int i:

这个用法是well-known:延迟赋值到以后。这最常用于创建字段 non-nullable,即使您可能不会立即获得该值。我相信你对这种用法很熟悉。

第二个用法,例如late int i = 0:

这是为了延迟值计算,直到访问该字段。这在值的计算成本很高时很有用,因此您可能希望将其计算延迟到第一次需要它时。它表示 on the official documentation:

When you do this, the initializer becomes lazy. Instead of running it as soon as the instance is constructed, it is deferred and run lazily the first time the field is accessed. In other words, it works exactly like an initializer on a top-level variable or static field. This can be handy when the initialization expression is costly and may not be needed.

所以基本上,取决于您是否立即分配一个值(在同一行),Dart 将决定您使用的是两种用法中的哪一种。如果你写 late int i 是第一次使用,如果你写 late int i = 0late int i = calculateValue() 是第二次使用:延迟计算直到访问字段 i首次。就像 Kotlin 中的 lateinit 或 Swift 中的 lazy

现在回到你的案例。通过在与 late 关键字相同的行上分配一个值,您正在使用第二种用法,基本上是“惰性初始化”,直到第一次访问该字段为止。当它被访问时,这个 class 已经被实例化,所以(到那个时候)你可以使用 this 关键字。