如何检查“迟到”变量在 Dart 中是否已初始化

tow*_*hid 8 variables initialization dart flutter

在 kotlin 中,我们可以检查 'late' 类型变量是否像下面这样初始化

lateinit var file: File    
if (this::file.isInitialized) { ... }
Run Code Online (Sandbox Code Playgroud)

有可能在 Dart 中做类似的事情吗?

om-*_*-ha 29

我根据不同 dart 维护者的建议以及我的自我分析得出了一些技巧:

late使用提示:

  • late如果您稍后要检查变量的初始化情况,请不要对变量使用修饰符。
  • 不要对late面向公众的变量使用修饰符,仅对私有变量(以 前缀_)使用。初始化的责任不应委托给 API 用户。编辑:正如Irhn 提到的late final,这条规则仅对于没有初始化表达式的变量才有意义,它们不应该是公共的。否则,存在公开late变量的有效用例。请看他的描述性评论!
  • 请确保late在所有构造函数、现有构造函数和新兴构造函数中初始化变量。
  • 在无法访问的代码场景中初始化变量时请务必小心late。例子:
    • late变量在if子句中初始化,但在 中没有初始化else,反之亦然。
    • 一些控制流短路/提前退出阻止执行到达late变量初始化的行。

如有错误/补充,请指出。

享受!

资料来源:


M12*_*123 14

不幸的是,这是不可能的。

从文档:

如果您需要检查它们是否已初始化,请避免使用后期变量。

Dart 无法判断后期变量是否已被初始化或分配。如果您访问它,它会立即运行初始化程序(如果有)或抛出异常。有时,您有一些延迟初始化的状态,而较晚可能很适合,但您还需要能够判断初始化是否已经发生。

尽管您可以通过将状态存储在后期变量中并使用单独的布尔字段来跟踪变量是否已设置来检测初始化,但这是多余的,因为 Dart 在内部维护后期变量的初始化状态。相反,它是 通常更清晰,使变量不晚,可为空。然后您 可以通过检查 null 来查看变量是否已初始化。

当然,如果 null 是变量的有效初始化值,那么拥有一个单独的布尔字段可能确实有意义。

https://dart.dev/guides/language/effective-dart/usage#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized

  • 我认为您应该强调此引用中显示的解决方案。我建议在末尾添加或加粗以使用非延迟且可为空的变量。 (4认同)

ert*_*ull 8

您可以创建一个 Late 类并使用如下扩展:

import 'dart:async';
import 'package:flutter/foundation.dart';

class Late<T> {
  ValueNotifier<bool> _initialization = ValueNotifier(false);
  late T _val;
  
  Late([T? value]) {
    if (value != null) {
      this.val = value;
    }
  }

  get isInitialized {
    return _initialization.value;
  }

  T get val => _val;

  set val(T val) => this
    .._initialization.value = true
    .._val = val;
}

extension LateExtension<T> on T {
  Late<T> get late => Late<T>();
}

extension ExtLate on Late {
  Future<bool> get wait {
    Completer<bool> completer = Completer();
    this._initialization.addListener(() async {
      completer.complete(this._initialization.value);
    });

    return completer.future;
  }
}
Run Code Online (Sandbox Code Playgroud)

使用 isInitialized 属性创建后期变量:

var lateString = "".late;
var lateInt = 0.late;
//or
Late<String> typedLateString = Late();
Late<int> typedLateInt = Late();
Run Code Online (Sandbox Code Playgroud)

并像这样使用:

print(lateString.isInitialized)
print(lateString.val)
lateString.val = "initializing here";

Run Code Online (Sandbox Code Playgroud)

即使你可以等待这个类的初始化:

Late<String> lateVariable = Late();

lateTest() async {
  if(!lateVariable.isInitialized) {
    await lateVariable.wait;
  }
  //use lateVariable here, after initialization.
}
Run Code Online (Sandbox Code Playgroud)


Jef*_*itz 7

如果有人在路上遇到它,可能会杀了你,但你可以将它包装在 try/catch/finally 中来进行检测。与单独的布尔值相比,我更喜欢它。

我们有一个实例,如果一个小部件加载失败并且包含一个在加载时填充的晚期控制器,则该小部件将被处置。由于控制器为空,处置失败,但这是控制器可以为空的唯一情况。我们将 dispose 包装在 try catch 中来处理这种情况。


Nie*_*els 7

使用可为空而不是延迟:

File? file;
File myFile;

if (file == null) {
    file = File();
}

myFile = file!;
Run Code Online (Sandbox Code Playgroud)

myFile = file!;请注意This Converts File?to中的感叹号File