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

时间:2017-03-17 18:38:06

标签: constructor dart final

在Java中,您可以这样做:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController as vm">
  <div ng-repeat="category in vm.allCategories track by category.id_cat">
    {{category.name}}
  </div>
</div>

在Dart,我试过:

class A {    
    private final int x;

    public A() {
        x = 5;
    }
}

我收到两个编译错误:

  

最终变量&#39; x&#39;必须初始化。

  

&#39; X&#39;不能用作定位器,因为它是最终的。

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

6 个答案:

答案 0 :(得分:40)

您可以实例化构造函数体中的最终字段。有一个特殊的语法:

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

答案 1 :(得分:18)

您可以使用构造函数中的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));
}

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

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

答案 2 :(得分:3)

我遇到了类似的问题:我试图从构造函数初始化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);
}
/// Demo class, to simulate constructing an object
/// from another object.
class Coordinates {
  final int x;
  final int y;
  final int z;
}

显然这可行。您可以使用上述语法(检查Point3d的构造函数)来初始化您的最终字段,并且效果很好!

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

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

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

答案 3 :(得分:3)

这里是初始化 final 类变量的方法的简化总结。

class MyClass {
  final int x; //     <-- initialize this
}

初始化值

class MyClass {
  final int x = 'hello'.length;
}

如果初始化只能在运行时完成,您将只使用 final。否则,static const 更好:

class MyClass {
  static const int x = 0;
}

初始化器形式

class MyClass {
  MyClass(this.x);
  final int x;
}

这是最常用的方法。

初始化列表

class MyClass {
  MyClass(int x) 
    : _x = x;
  final int _x;
}

当您想将字段保密时,这很有用。

默认参数值

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

class MyClass {
  MyClass({this.x = 0});
  final int x;
}

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

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

class MyClass {
  MyClass({int? x}) 
    : _x = x ?? 0;
  final int _x;
}

后期初始化

class MyClass {
  MyClass(String? a) {
    x = a?.length ?? 0;
  }
  late final int x;
}

如果您需要进行比初始化列表中允许的更复杂的初始化,这将很有用。例如,我在 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;
  }
}

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

这不会初始化 x

final myClass = MyClass();

但这确实初始化了x

final myClass = MyClass();
final value = myClass.x;

答案 4 :(得分:2)

在这里我遇到了一个难题,我想初始化一个没有任何项目的最终List,并在构造函数内部定义一个Stream(在这种情况下,例如distanceFromOrigin)。

我无法用下面的任何答案来做到这一点,但是我将它们混合在一起,并且奏效了。

示例:

class MyBloc {
  final BehaviorSubject<List<String>> itemsStream;
  final List<String> items = [];

  MyBloc() : this.itemsStream = BehaviorSubject<List<String>>.seeded([]) {
    items.addAll(List.generate(20, (index) => "Hola! I'm number $index"));
    itemsStream.add(items);
  }
}

答案 5 :(得分:0)

class A{
  final int x;
  
  A(this.x){
  }
  
}