如何正确初始化延迟变量

How do I properly initialize a late variable

我有一个迟到的属性(_bmi)默认设置为null,然后我在方法calcBMI()中初始化它,在初始化之后,我将它的值用在两个更多方法,resultinterpretation 来满足一些布尔条件,但我 运行 变成了 lateinitialisationerror,因为第一个方法 (result()) 不识别我在 calcBMI() 中初始化的值,它默认为 _bmi 属性 具有的初始空值,但是 interpretation() 方法识别初始化值。我怎么知道这只是第一个不识别它的方法是因为当我将一个值传递给 _bmi 属性 时,当我设置它时,应用程序不会抛出错误,它有效,但随后它使用第一种方法的设置值,但第二种方法使用 calcBMI() 的初始化值,我做错了什么,这是代码。

class CalculatorBrain {
  CalculatorBrain({required this.weight, required this.height});

  int weight;
  int height;
  late double _bmi = 30; // when I set this value, result() works with it, but interpretation() works with the value passed in calcBMI();

  String calcBMI() {
    _bmi = weight / pow(height / 100, 2);
    return _bmi.toStringAsFixed(1);
  }

  String result() {
    if(_bmi >= 25) {
      return 'overweight';
    } else if(_bmi > 18.5) {
      return 'normal';
    } else {
      return 'underweight';
    }
  }

  String interpretation() {
    if(_bmi >= 25) {
      return 'You have a higher than normal body weight. Try to exercise more.';
    } else if(_bmi > 18.5) {
      return 'You have a normal body weight. Good job.';
    } else {
      return 'You have a lower than normal body weight. You can eat a bit more.';
    }
  }

}

这是我使用 class

的地方
BottomButton(
              onTap: () {
                CalculatorBrain calc = CalculatorBrain(
                  weight: weight,
                  height: height,
                );
                setState(() {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) {
                          return ResultsPage(result: calc.result(), bMI: calc.calcBMI(), interpretation: calc.interpretation());
                        }
                    ),
                  );
                });
              },
              title: 'CALCULATE',
            ),

late 修饰符意味着您将在某个时候定义它,您在 calcBMI() 中正在这样做,之后您调用 interpretation(),其中 _bmi 已经有一个值。 如果您只是调用 result(),您的代码将崩溃,因为 _bmi 仍未定义。

如果你之前有一个LateInitializationError,那不是“[result()]无法识别我在calcBMI()中初始化的值”,而是你调用了[=17] =] 在你打电话给 calcBMI().

之前

_bmi 一个初始值避免了 LateInitializationError,但你仍然有同样的基本问题:你正在阅读 _bmi before 您调用 calcBMI() 为其分配您实际想要的值。

特别是,您有:

return ResultsPage(result: calc.result(), bMI: calc.calcBMI(), interpretation: calc.interpretation());

Dart 按 left-to-right 顺序计算函数参数,因此您将首先调用 calc.result(),然后是 calc.calcBMI(),然后是 calc.interpretation()。更改顺序应该可以解决您的问题:

return ResultsPage(
  bMI: calc.calcBMI(),
  result: calc.result(),
  interpretation: calc.interpretation(),
);

但是,依赖参数评估顺序是一种糟糕的风格。读者(包括你未来的自己)不会明显看出参数顺序很重要。明确排序 order-dependent:

的操作会好得多
var bmi = calc.calcBMI();
return ResultsPage(
  result: calc.result(),
  bMI: bmi,
  interpretation: calc.interpretation(),
);

请注意,这与 _bmi 成为 late 无关。将 _bmi 声明为 late 在您当前编写的代码中没有任何意义,您可以将其删除。但是您还应该考虑重写您的代码,以减少 CalculatorBrain 对消费者以特定顺序调用其方法的依赖。一些可能性:

动态计算_bmi

您可以使 _bmi 成为 getter,在每次访问时计算 weight/height 的正确值:

class CalculatorBrain {
  CalculatorBrain({required this.weight, required this.height});

  int weight;
  int height;

  double get _bmi => weight / pow(height / 100, 2);

  String calcBMI() => _bmi.toStringAsFixed(1);

  String result() {
    final _bmi = this._bmi;
    if(_bmi >= 25) {
      return 'overweight';
    } else if(_bmi > 18.5) {
      return 'normal';
    } else {
      return 'underweight';
    }
  }

  ...

恰好计算_bmi一次

如果你使 weight/height final,那么你可以计算 _bmi 一次并完成:

class CalculatorBrain {
  CalculatorBrain({required this.weight, required this.height});

  final int weight;
  final int height;

  // `late` computes `_bmi` lazily, which is necessary because it depends on
  // `weight` and `height`.
  late final double _bmi = weight / pow(height / 100, 2);

  ...

如果 weightheight 更改

,则自动更新 _bmi

如果 weight/height 必须是可变的,那么您可以创建设置器以便 _bmi 始终自动更新:

class CalculatorBrain {
  CalculatorBrain({required int weight, required int height})
    : _weight = weight,
      _height = height {
    _updateBmi();
  }

  late double _bmi;

  int _weight;
  int get weight => _weight;
  set weight(int value) {
    _weight = value;
    _updateBmi();
  }

  int _height;
  int get height => _height;
  set height(int value) {
    _height = value;
    _updateBmi();
  }

  void _updateBmi() {
    _bmi => weight / pow(height / 100, 2);
  }

  ...