如何在构造函数中初始化最终的类属性?

Bla*_*bam 44 constructor final dart

在Java中,您可以这样做:

class A {    
    private final int x;

    public A() {
        x = 5;
    }
}
Run Code Online (Sandbox Code Playgroud)

在达特,我试过:

class A {    
    final int x;

    A() {
        this.x = 5;
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到两个编译错误:

必须初始化最终变量'x'.

'x'不能用作定位器,因为它的最终版本.

有没有办法在Dart的构造函数中设置最终属性?

w.b*_*ian 67

无法在构造函数体中实例化最终字段.有一个特殊的语法:

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  // Old syntax
  // Point(x, y) :
  //   x = x,
  //   y = y,
  //   distanceFromOrigin = sqrt(pow(x, 2) + pow(y, 2));

  // New syntax
  Point(this.x, this.y) :
    distanceFromOrigin = sqrt(pow(x, 2) + pow(y, 2));
}
Run Code Online (Sandbox Code Playgroud)

  • 并在其末尾添加 ```, super(key: key)``` 。 (3认同)
  • 我找到了问题的答案:只需用逗号分隔两条指令即可。请注意,super() 调用必须是最后一件事。 (2认同)
  • @OliverDixon 我发现这是有效的``dart class Point {final num x; 最终的 y 数;最终距离原点的距离;最终 num 从原点 2 的距离;Point(this.x, this.y) : distanceFromOrigin = sqrt(pow(x, 2) + pow(y, 2)), distanceFromOrigin2 = sqrt(pow(x, 2) + pow(y, 2)); } ``` (2认同)

rkj*_*rkj 27

您可以使用this.构造函数中的语法使其更短(在https://www.dartlang.org/guides/language/language-tour#constructors中描述):

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(this.x, this.y)
      : distanceFromOrigin = sqrt(pow(x, 2) + pow(y, 2));
}
Run Code Online (Sandbox Code Playgroud)

如果你有一些更复杂的初始化,你应该使用工厂构造函数,代码变为:

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point._(this.x, this.y, this.distanceFromOrigin);

  factory Point(num x, num y) {
    num distance = distanceFromOrigin = sqrt(pow(x, 2) + pow(y, 2));
    return new Point._(x, y, distance);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 迟到的问题但是工厂关键字在这里做什么。我以为它是用来决定是返回一个现有的还是新的对象,但你总是在这里返回一个新的对象,对吧 (3认同)
  • 需要工厂,因为不能立即创建 Point 对象 - 我们首先需要计算“距离”,然后我们就准备好初始化所有最终变量。 (2认同)
  • “factory”关键字告诉您需要自己构建返回值(与不使用它相反,它将为您创建)。 (2认同)

Snu*_*ies 7

我有一个类似的问题:我试图final从构造函数初始化一个字段,同时调用一个超级构造函数。你可以考虑下面的例子

class Point2d {
  final int x;
  final int y;

  Point2d.fromCoordinates(Coordinates coordinates)
      : this.x = coordinates.x,
        this.y = coordinates.y;
}

class Point3d extends Point2d {
  final int z;

  Point3d.fromCoordinates(Coordinates coordinates)
      :this.z = coordinates.z,
        super.fromCoordinates(coordinates);
}
Run Code Online (Sandbox Code Playgroud)
/// Demo class, to simulate constructing an object
/// from another object.
class Coordinates {
  final int x;
  final int y;
  final int z;
}
Run Code Online (Sandbox Code Playgroud)

那么显然这有效。您可以使用上述语法(检查 Point3d 的构造函数)初始化最终字段,它工作得很好!

运行一个这样的小程序来检查:

void main() {
  var coordinates = Coordinates(1, 2, 3);
  var point3d = Point3d.fromCoordinates(coordinates);
  print("x: ${point3d.x}, y: ${point3d.y}, z: ${point3d.z}");
}
Run Code Online (Sandbox Code Playgroud)

它应该打印 x: 1, y: 2, z: 3


Sur*_*gch 7

这是初始化 final 类变量的方法的简化摘要。

class MyClass {
  final int x; //     <-- initialize this
}
Run Code Online (Sandbox Code Playgroud)

初始化值

class MyClass {
  final int x = 'hello'.length;
}
Run Code Online (Sandbox Code Playgroud)

final当初始化只能在运行时完成时才使用。否则,static const更好:

class MyClass {
  static const int x = 0;
}
Run Code Online (Sandbox Code Playgroud)

初始化器形式

class MyClass {
  MyClass(this.x);
  final int x;
}
Run Code Online (Sandbox Code Playgroud)

这是最常见的方法。

初始化列表

class MyClass {
  MyClass(int x) 
    : _x = x;
  final int _x;
}
Run Code Online (Sandbox Code Playgroud)

当您想保持字段私有时,这很有用。

默认参数值

[]对于未命名参数,您可以使用方括号 ( ) 将参数括起来,或者使用大括号 ( {}) 将命名参数括起来,然后为其指定默认值。

class MyClass {
  MyClass({this.x = 0});
  final int x;
}
Run Code Online (Sandbox Code Playgroud)

如果您想让参数可选,这很有用。

你也可以用初始化列表完成同样的事情:

class MyClass {
  MyClass({int? x}) 
    : _x = x ?? 0;
  final int _x;
}
Run Code Online (Sandbox Code Playgroud)

后期初始化

class MyClass {
  MyClass(String? a) {
    x = a?.length ?? 0;
  }
  late final int x;
}
Run Code Online (Sandbox Code Playgroud)

如果您需要进行比初始化列表中允许的更复杂的初始化,这将非常有用。例如,我在 Flutter 中初始化手势识别器时就这样做了。

延迟初始化

使用的另一个优点late是它不会在您访问该值之前初始化该值。

class MyClass {
  late final int x = _doHeavyTask();
  int _doHeavyTask() {
    var sum = 0;
    for (var i = 0; i < 100000000; i++) {
      sum += 1;
    }
    return sum;
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您有一个繁重的计算,而您只想在绝对需要时调用,这将非常有用。

这不会初始化x

final myClass = MyClass();
Run Code Online (Sandbox Code Playgroud)

但这确实初始化x

final myClass = MyClass();
final value = myClass.x;
Run Code Online (Sandbox Code Playgroud)