简体   繁体   English

Flutter:延迟初始化有状态小部件中的“小部件点”类级变量——这是怎么回事?

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

Consider the following class level property inside the state class of a stateful widget:考虑有状态小部件的 state class 内的以下 class 级别属性:

int myInt = widget.int;

Android Studio informs that: "The instance member 'widget' can't be accessed in an initializer." Android Studio 通知:“无法在初始化程序中访问实例成员‘widget’。”

(I understand what this error means). (我明白这个错误是什么意思)。

So then if we add the late keyword, it appears to be fine:那么如果我们添加 late 关键字,它似乎没问题:

late int myInt = widget.int;

However... this is surprising to me that I'm allowed to do all that in one line — I thought that late variables had to be not set/set as null:然而......令我惊讶的是我被允许在一行中完成所有这些 - 我认为晚期变量必须不设置/设置为 null:

late int myInt;

... and then assign inside onInit. ...然后在 onInit 内部分配。

Since I didnt declare when to assign it, I dont know when the assignment takes place.由于我没有声明何时分配它,所以我不知道分配何时发生。

The question is:问题是:

Is the one-liner “late int myInt = widget.int;”一行代码是“late int myInt = widget.int;” exactly equivalent to assigning it myself in the initState method?完全等同于在 initState 方法中自己赋值?

The late keyword in Dart has 2 distinct usages, melt into a single keyword. Dart 中的late关键字有两种不同的用法,融合为一个关键字。


The first usage, eg late int i :第一种用法,例如late int i

This usage is well-known: delay assigning a value until later.这种用法是众所周知的:延迟分配一个值,直到以后。 This is most commonly used to make a field non-nullable, even though you might not have the value right away.这最常用于使字段不可为空,即使您可能不会立即获得该值。 I'm sure you are familiar with this usage.我相信您对这种用法很熟悉。

The second usage, eg late int i = 0 :第二种用法,例如late int i = 0

This is to delay the value calculation until the field is being accessed.这是为了延迟值计算,直到访问该字段。 This is useful when the value is expensive to calculate, so you might want to delay its calculation until it's needed for the first time.这在值的计算成本很高时很有用,因此您可能希望将其计算延迟到第一次需要它时。 It's stated 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.换句话说,它的工作方式与顶级变量或 static 字段上的初始值设定项完全相同。 This can be handy when the initialization expression is costly and may not be needed.当初始化表达式代价高昂并且可能不需要时,这会很方便。

So basically, depends on whether you assign a value right away (on the same line), Dart will decide which of the 2 usages you are using.所以基本上,取决于你是否立即分配一个值(在同一行),Dart 将决定你使用的是两种用法中的哪一种。 If you write late int i it will be the first usage, if you write late int i = 0 or late int i = calculateValue() it will be the second usage: delay the calculation until when the field i is accessed for the first time.如果你写late int i会是第一次使用,如果你写late int i = 0late int i = calculateValue()会是第二次使用:延迟计算直到字段i第一次被访问时. It's like lateinit in Kotlin or lazy in Swift.就像lateinit中的 lateinit 或 Swift 中的lazy

Now back to your case.现在回到你的情况。 By assigning a value on the same line as the late keyword, you are using the second usage, basically "lazy init" until the field is accessed for the first time.通过在与late关键字相同的行上分配一个值,您使用的是第二种用法,基本上是“惰性初始化”,直到第一次访问该字段为止。 By the time it's accessed, this class would've been instantiated, so (by that time) you are allowed to use the this keyword.当它被访问时,这个 class 已经被实例化,所以(到那个时候)你可以使用this关键字。

In the first case Android studio throws that error because int myInt requires a value the moment you are declaring it.在第一种情况下 Android studio 会抛出该错误,因为int myInt在您声明它时需要一个值。

In that particular moment, in the Statefull widget state, the widget object is not accessible.在那个特定时刻,在 Statefull 小部件 state 中, widget object 不可访问。

In the second case:在第二种情况下:

late int myInt = widget.int;

That is a valid one line declaration and assignment of the variable, but the effect is a bit different from the onInit alternative.这是有效的一行声明和变量赋值,但效果与onInit替代方案有点不同。

The late keyword works in a lazy way. late 关键字以lazy方式工作。 Instead of running as soon as the instance is built, it run the first time the field is used.它不是在构建实例后立即运行,而是在第一次使用该字段时运行。 In that moment the widget object will be accessible.在那一刻, widget object 将可以访问。

Take a look at the answer to this question, it can be helpful: here看看这个问题的答案,它会有所帮助: 这里

Assigning the value inside the onInit guarantees that the value is actually assigned only once when the widget is initialized.onInit内部分配值可确保在初始化小部件时仅实际分配一次值。

widget.xxx corresponds to the value of xxx of the instance of a widget, ie the widget once it exists. widget.xxx对应一个widget实例的xxx的值,即widget一旦存在。

So when you use widget.xxx in initialisation of the widget, the var xxx does not exists.因此,当您在小部件的初始化中使用widget.xxx时,var xxx不存在。

That's why the dart compiler tell you The instance member 'widget' can't be accessed in an initializer .这就是为什么 dart 编译器告诉您The instance member 'widget' can't be accessed in an initializer原因。

By adding the keyword late in front of the declaration, you tell the compiler that this variable will be defined later.通过在声明前添加关键字 late,您告诉编译器该变量将在稍后定义。

But be careful, it will then really have to be defined later (in initState for example) and in any case before any use.但是要小心,它真的必须稍后定义(例如在 initState 中)并且在任何情况下都必须在使用之前定义。

This error comes from the fact that dart is now a null safety aware language.这个错误是因为 dart 现在是 null 安全感知语言。

That is to say a language that strives to ensure that no variabales can have a null value.也就是说,一种努力确保没有变量可以具有 null 值的语言。 This is for reasons of code quality and greater code security.这是出于代码质量和更高代码安全性的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM