爲了測試我對Dart的理解,我製作了一個2D不可變的矢量,它不僅存儲它的x和y分量,還存儲它的角度和長度。只有在x和y值的構造下才會計算它們。我很快意識到最終字段需要使用初始值設定項列表或this
-參數快捷鍵進行設置,這些快捷鍵不允許使用很多計算值。就像this answer指出的那樣,我必須使用工廠構造函數來創建我的向量,使其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);
}
但它引起了我的注意,我無法使工廠構造函數爲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)));
但只要我儘量做到常量,它告訴我,在初始化列表中的代碼包含非編譯時常量。
我可以在飛鏢中找到的唯一不變的矢量是here on 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));
那麼應該是我的結論呢?我錯過了一個使這成爲可能的特性,還是我應該放棄使用const作爲這個類?
我是這麼想的。在那種情況下,我只會擺脫const,讓我的類變得不那麼健壯,似乎不是合乎邏輯的事情。 –
如果你試圖讓這些實例不可變,那麼這個類不需要是const的,只是沒有辦法修改它的數據字段。 –
是的,我意識到這一點,我只是認爲用const進行優化會很好。但我可能試圖優化太早,我應該現在做一個遊戲,而不是:) –