Dart 立即分配给变量还是在构造函数中? [英] Dart assigning to variable right away or in constructor?

查看:19
本文介绍了Dart 立即分配给变量还是在构造函数中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Dart 中,立即赋值与 Java 中的构造函数是否有区别?

In Dart, is there a difference in assigning values right away vs in constructor like in Java?

class Example {
    int x = 3;
}

对比

class Example {
    int x;
    Example() {
        x = 3;
    }
}

我问是因为当我使用 Flutter 并尝试将使用 setState 的 Function 分配给变量时,前一种方法无法实现,而后一种方法可以实现.

I ask because when I was using Flutter and tried to assign a Function that uses setState to a variable, it was not possible with the former method but possible with the latter.

推荐答案

在你的小事上,没关系.

In your trivial case, it doesn't matter.

一般来说,可以通过以下几种方式来初始化实例变量:

In general, you can initialize instance variables in a few ways:

class Example1 {
  T x = value;
}

优点:

  • 直接、简洁.
  • 成员将在所有构造函数中初始化.
  • 可用于初始化final 或不可为空的成员.
  • 在调用基类构造函数之前初始化成员,这在基类构造函数调用被派生类覆盖的成员函数时很重要.
  • Direct, concise.
  • Member will be initialized in all constructors.
  • Can be used to initialize final or non-nullable members.
  • Member is initialized before invoking base class constructors, which is important when the base class constructor calls member functions that are overridden by the derived class.

缺点:

  • Cannot depend on construction arguments.
  • Usually cannot depend on this since the initialization occurs before this becomes valid (i.e., cannot depend on other instance members). (An exception is if the member is initialized lazily by declaring it late. This requires the null-safety feature to be enabled.)
class Example2 {
  T x;

  Example2() : x = value;
}

优点:

  • 可用于初始化final 或不可为空的成员.
  • 在调用基类构造函数之前初始化成员,这在基类构造函数调用被派生类覆盖的成员函数时很重要.
  • 可以利用构造参数.
  • 初始化变量总是引用一个成员变量,从不引用一个构造函数参数.
  • Can be used to initialize final or non-nullable members.
  • Member is initialized before invoking base class constructors, which is important when the base class constructor calls member functions that are overridden by the derived class.
  • Can utilize construction arguments.
  • The initialized variable always refers to a member variable, never to a constructor parameter.

缺点:

  • 如果类有多个构造函数,则需要重复初始化,或者构造函数应该重定向到公共构造函数.
  • 不能依赖于 this,因为初始化发生在 this 生效之前(即,不能依赖于其他实例成员).
  • 只能初始化封闭类的成员.因为初始化列表是在调用基类构造函数之前执行的,所以它们不能设置基类成员.
  • If the class has multiple constructors, initialization would need to be duplicated, or constructors should redirect to a common constructor.
  • Cannot depend on this since the initialization occurs before this becomes valid (i.e., cannot depend on other instance members).
  • Can initialize only members of the enclosing class. Because initializer lists are executed before invoking base class constructors, they cannot set base class members.
class Example3 {
  T x;

  Example3() {
    x = value;
  } 
}

优点:

  • 可以利用构造参数.
  • 可用于执行更复杂的初始化,例如无法通过单个表达式初始化成员的情况.
  • 可以使用this(即可以使用其他实例成员).
  • 可用于设置基类成员.
  • Can utilize construction arguments.
  • Can be used to perform more complicated initialization, such as cases where the member cannot be initialized via a single expression.
  • Can use this (i.e., can use other instance members).
  • Can be used to set base class members.

缺点:

  • 不能用于初始化 final 或不可为 null 的成员.
  • 如果类有多个构造函数,则需要重复初始化或重构初始化代码(例如但不限于重定向到公共构造函数).
  • 成员在调用基类构造函数之后被初始化.
  • 如果构造函数有一个隐藏成员变量的参数,很容易意外引用参数而不是成员.(参见 https://github.com/dart-lang/linter/issues/2552 了解详情.)
  • Cannot be used to initialize final nor non-nullable members.
  • If the class has multiple constructors, initialization would need to be duplicated or initialization code would need to be refactored out (such as, but not limited to, redirecting to a common constructor).
  • Member is initialized after invoking base class constructors.
  • If the constructor has a parameter that shadows a member variable, it's easy to accidentally refer to the parameter instead of the member. (See https://github.com/dart-lang/linter/issues/2552 for details.)

我可能忘记了一些要点,但我认为应该涵盖主要内容.

There probably are some points I'm forgetting, but I think that should cover the main ones.

直接,内联初始化首先发生,然后是初始化列表,然后是构造函数体.另见在参数列表和初始化列表中赋值的区别,这解释了为什么this变得有效仅用于对象初始化的后期.

Direct, inline initialization occurs first, then initialization lists, then constructor bodies. Also see Difference between assigning the values in parameter list and initialiser list, which explains why this becomes valid only for the later stages of object initialization.

举个例子,说明成员的初始化位置很重要:

As an example where it matters where members are initialized:

class Base {
  Base() {
    doSomething();
  }

  void doSomething() {}
}

class DerivedEarly extends Base {
  int? x;

  DerivedEarly() : x = 42;

  @override
  void doSomething() => print(x);
}

class DerivedLate extends Base {
  int? x;

  DerivedLate() {
    x = 42;
  }

  @override
  void doSomething() => print(x);
}

void main() {
  DerivedEarly(); // Prints: 42
  DerivedLate(); // Prints: null
}

这篇关于Dart 立即分配给变量还是在构造函数中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆