Dom*_*ino 5 constructor factory constants dart
为了测试我对 Dart 的理解,我制作了一个 2D 不可变向量,它不仅存储了它的 x 和 y 分量,还存储了它的角度和长度。它们仅在构建时根据 x 和 y 值计算。我很快意识到需要使用初始化列表或this-parameter 快捷方式设置最终字段,这不允许太多计算值。就像这个答案指出的那样,我不得不使用工厂构造函数从其 x 和 y 分量中创建我的向量。工厂构造函数然后在调用私有构造函数之前验证输入并计算长度和角度。
import 'dart:math';
class ImmutableVector {
// private fields
final double _x;
final double _y;
final double _angle;
final double _length;
// getters
double get x => _x;
double get y => _y;
double get angle => _angle;
double get length => _length;
/// Constructs a vector out of cartesian components.
///
/// Converts both arguments to doubles.
/// Null values will be treated as zeroes.
factory ImmutableVector.xy(num x, num y) {
x ??= 0.0;
y ??= 0.0;
x = x.toDouble();
y = y.toDouble();
var angle = atan2(y, x) % (2*PI);
var length = sqrt(pow(x, 2) + pow(y, 2));
return new ImmutableVector._raw(x, y, angle, length);
}
/// Constructs a vector by setting the fields directly.
const ImmutableVector._raw(this._x, this._y, this._angle, this._length);
}
Run Code Online (Sandbox Code Playgroud)
但是我注意到我不能将工厂构造函数设为 const,因为 const 工厂只能重定向构造函数。绝对没有办法让我的向量在其构造函数中包含代码,并且仍然使用 const 构造函数使其不可变吗?如果是这样,为什么?
我还会提到,如果传递的值为空,我曾经抛出错误,但我将其默认为零,因此我实际上可以使用初始化列表。然后我尝试这样做,结果当构造函数不是工厂时它可以工作:
ImmutableVector.xy(num x, num y) : this._raw(
x = (x ?? 0.0).toDouble(),
y = (y ?? 0.0).toDouble(),
atan2(y, x) % (2*PI),
sqrt(pow(x, 2) + pow(y, 2)));
Run Code Online (Sandbox Code Playgroud)
但是一旦我尝试将其设置为 const,它就会告诉我初始化程序列表中的代码包含非编译时常量。
我能在 dart 中找到的唯一不可变向量在 GitHub 上,它不会对构造函数参数进行任何类型的空验证或计算,完全依赖于方法会在某个点在空向量上中断的事实。由于强制初始化列表,它还有一个构造函数,可以从另一个具有较差性能和重复性的单元向量中创建一个单元向量:
const Vector.unit(final num x, final num y, final num z) :
this(x / PMath.len(x, y, z), y / PMath.len(x, y, z), z / PMath.len(x, y, z));
Run Code Online (Sandbox Code Playgroud)
那么我的结论应该是什么?我是否错过了使这成为可能的功能,或者我应该放弃对此类使用 const 吗?
Dart 在编译期间不执行 Dart 代码。这就是const构造函数不能拥有主体的原因,也是没有其他方法可以解决此限制的原因。
如果您想在创建实例时执行代码,请不要使用const. 无论如何,Const 在 Dart 中并不是那么重要。甚至有人讨论将其从语言中删除,因为好处还不够大。