如何检查 'late' 变量是否已在 Dart 中初始化

How to check 'late' variable is initialized in Dart

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

lateinit var file: File    
if (this::file.isInitialized) { ... }

是否可以在 Dart 中做类似的事情..?

很遗憾,这是不可能的。

来自文档:

AVOID late variables if you need to check whether they are initialized.

Dart offers no way to tell if a late variable has been initialized or assigned to. If you access it, it either immediately runs the initializer (if it has one) or throws an exception. Sometimes you have some state that’s lazily initialized where late might be a good fit, but you also need to be able to tell if the initialization has happened yet.

Although you could detect initialization by storing the state in a late variable and having a separate boolean field that tracks whether the variable has been set, that’s redundant because Dart internally maintains the initialized status of the late variable. Instead, it’s usually clearer to make the variable non-late and nullable. Then you can see if the variable has been initialized by checking for null.

Of course, if null is a valid initialized value for the variable, then it probably does make sense to have a separate boolean field.

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

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

我们有一个实例,如果小部件无法加载并包含一个在加载时填充的延迟控制器,则会将其丢弃。由于控制器为空,因此处理失败,但这是控制器可以为空的唯一情况。我们将 dispose 包裹在一个 try catch 中来处理这种情况。

您可以创建 Late class 并使用如下扩展:

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;
  }
}

用isInitialized创建后期变量属性:

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

并像这样使用:

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

甚至你可以等待初始化 class:

Late<String> lateVariable = Late();

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

我从不同的 dart 维护者的建议中得出的一些技巧,以及我的自我分析:

late使用技巧:

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

请指出任何errors/additions。

尽情享受吧!

来源:

我在初始化后期变量时使用布尔变量。 我的情况是: 我正在使用音频播放器,我需要一个 dart 文件中的流。

我正在分享我的代码块,这种方法可以使用全局布尔变量轻松实现到项目中。 我的问题是当用户快速打开和关闭页面时我从处理方法中得到的异常