2017-10-28 76 views
1

根據this excellent explanationconst Dart中的表達式是「深不可變的」,這意味着裏面沒有任何東西可以改變,因此整個表達式總是表示相同的東西。這對於編譯器非常有用,因爲它可以一次生成整個對象圖形,並在每次出現這種表達時重新使用它,而且程序員知道這樣一個表達式 - 即使是深度嵌套 - 仍然是靜止的遵循價值語義,不會在我背後做任何事情。Const構造函數與靜態最終規範值

我正在使用編譯器的這些優化來使用一個結構良好的對象模型(而不是在位向量中手動編碼它),並且仍然獲得良好的性能。既然我們可以通過用「明確散列」某些值來獲得其中的一些好處,使用它們的運行時常量,這個問題就出現了,在這種情況下,哪個是好的風格?

請看下面的例子:

enum ShaftType { RING, SUN, CARRIER } 

class Shaft { 
    final int index; 
    final ShaftType type; 

    Shaft(this.type, this.index) { 
    assert((type == ShaftType.CARRIER) == (index == null)); 
    } 
    const Shaft.CARRIER() 
     : type = ShaftType.CARRIER, 
     index = null; 
    const Shaft.RING(this.index) : type = ShaftType.RING; 
    const Shaft.SUN(this.index) : type = ShaftType.SUN; 
} 

class GearPath { 
    final Shaft input, output, fixed; 

    GearPath({this.input, this.output, this.fixed}) { 
    // input and output must be set 
    assert(null != input && null != output); 

    // fixed shaft can't be anything else 
    assert(fixed != input && fixed != output); 
    } 

    GearPath.carrierToFirstRingFixedSun(int i) 
     : input = const Shaft.CARRIER(), 
     output = const Shaft.RING(0), 
     fixed = new Shaft.SUN(i) {} 

    static final singleFixedSunUp = new GearPath(
    input: const Shaft.CARRIER(), 
    output: const Shaft.RING(0), 
    fixed: const Shaft.SUN(0), 
); 

    static final directDrive = new GearPath(
    input: const Shaft.CARRIER(), 
    output: const Shaft.CARRIER(), 
    fixed: null, 
); 

    // ... 
} 

我不能讓主Shaft(..)GearStage(..)構造const,因爲我要檢查一些限制,但我可以提供特殊構造的情況下(如Shaft.SUN(int i)Shaft.CARRIER() ),它們通過設計符合這些限制(至少部分),併爲用戶提供對這些共同價值的可讀短文。

另一方面,當一個const構造函數沒有參數時,我就可以像GearStage.directDrive那樣將它寫成static final成員。如果所有用戶都引用此靜態成員而不是再次重新創建值,那麼我們還可以享受共享內存和快速比較(引用同一對象)的好處。我無法將此定義的右側聲明爲const,因爲它使用非常量構造函數,但是開發人員可以從上下文中看到,這確實是一個常量值,而不是靜態字段中隱藏的全局可變單例。所以出於實際的目的,它應該和const構造函數一樣好,對吧?

由於我沒有發現這描述了任何作爲最佳實踐的地方,我的問題就是如果這確實是一種在const構造函數和static final「命名值實例」之間進行組合和折衷的好方法?

最後,我想知道是否有一種方法可以將GearPath.carrierToFirstRingFixedSun(int i)也作爲一個const構造函數聲明?目前我不能因爲const Shaft.SUN(i)抱怨i不是恆定的。

full code of example

回答

2

飛鏢2將允許你有聲稱在常量構造函數(只要你的條件可以計算爲一個常數表達式)。 然後你就可以寫:

GearPath({this.input, this.output, this.fixed}) 
    : // input and output must be set 
    assert(null != input && null != output), 
    // fixed shaft can't be anything else 
    assert(!identical(fixed, input) && !identical(fixed, output)); 

在那之前,你不能兼得驗證和常量表達式。

您仍然無法生成GearPath.carrierToFirstRingFixedSun(int i)常量,因爲它的i不是常量。即使i是const構造函數的參數,const Shaft.SUN(i)仍然不是有效的const表達式。每個const Constructor(...)調用仍然必須創建一個對象,即使它發生在另一個const構造函數的初始化程序列表中。作爲一個經驗法則,您應該考慮將值暴露爲常量而不是最終值是您想要承諾的。當你創建變量const時,這意味着其他人可以在另一個const表達式中使用該值,然後將該變量更改爲final將是一次重大更改。說什麼是const是你應該故意選擇的承諾,不僅僅是因爲你可以。所以,考慮你的變量的用例。如果你沒有看到它在其他const表達式中被使用,那麼就把它做成final。