Dart基礎 — 老子只做一次的Constant
左側 Const — 修飾 Variable
先來看個官方的定義
a const variable is a compile-time constant
// 被 const 修飾的 variable 在編譯時就是一個常數
寫法會長這樣:
const name1 = '李小白';
const String name2 = '王小明';
所謂左側的 const 就是在等號左側的 const,像上述的例子 const 就是為了宣告 name1 / name2 這兩個 String Variable 是個 Constant 常數。
那這樣他跟 final有什麼區別咧!?
與 Final 的差異
兩者都是為了宣告一個不可變動的 property。
唯一的區別為『時機點』。
Final 宣告的 property 是在專案執行(run time)階段的常數。
Constant 宣告的 property 是在專案編譯(compile time)階段的常數。
final date1 = DateTime.now();
const date2 = DateTime.now(); //compile error
由於 DateTime.now() 會直到專案執行到該行時,才會去取得最終的日期時間,所以不符合 const 的規則。
const 所修飾的 variables 必須在寫完的那一瞬間就要決定 value 是什麼。
const 遇到 class
凡是 const 修飾的是 class 層級的 variable,其必須為 static。
class MediaManager{
static const type = "mp3";
const String name = "media manager"; //compile error
}
這個規定的原因還是一樣在 compile time 上。
如果你熟悉 static 這個 keyword,你就會知道這個 keyword 是直接隸屬於 class,他不需要實體後的物件才可以存在。
然而實體後的物件僅存在於 run time 上,故 class 層級的 const 必須使用 static 來確保在編譯時值就已經決定好了。
但總的來說,雖然 const 跟 final 還有這樣的差異。
但說實在的,好像對寫程式沒有什麼驚天動地的幫助。
那為什麼這個東西需要存在呢?如果我從頭到尾都不用 const 會有什麼是發生呢?
我初步的結論是,不會有任何差異。你大可從頭到尾都不要使用 const ,用 final 一路從小怪打到大魔王。
那這樣 const 好像沒有什麼價值。
直到我找到了這篇文章 — The flutter “const” Keyword demystified.
才發覺 const 真正有價值的地方不在等號左側,而是等號右側!
右側 Const — 修飾 Value
官方文件說明如下
The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant value.
給翻譯翻譯就是,const 不只可以宣告『常數的variables』(等號左側時),也可以用來宣告一個 『常態的 value』(等號右側時)。
前面提到的文章作者是這樣子解釋 const 的
The actual use of the const keyword is to serve as an indicator that tells the compiler that, “for this variable, it will never change in the lifetime of this code, so create just one copy of it and where ever it is mentioned, just reference back to the one copy you already created and don’t create a new one.”
const 這個關鍵字的用處是告訴編譯器『被我標注過後的東西,你就做一次就好了,啊如果有別的地方要用,就複製拿過去用就好了。』
該作者舉例,在 Flutter 所有 UI 的基礎單位都是 widget 的情況下,每個 widget 都是一個 class。
開發者在特定情況下需要出 100 個一模一樣的 layout,如果用一般的方式產出的話,對記憶體來說是一大浪費,但如果你今天使用 const 的話就不一樣了。
我的理解是,const 他老人家只做過一次,只花費一次的記憶體空間。
何樂而不為。
List<int> numberList1 = const [1,2,3,4,5];
List<int> numberList2 = const [1,2,3,4,5];
List<int> numberList3 = [1,2,3,4,5];print(numberList1 == numberList2); //true
print(numberList1 == numberList3); //false
這是 const 在右側的標準寫法,他所修飾的是 [1,2,3,4,5] 這個 value。
const 告知 compiler [1,2,3,4,5] 這一組陣列只需要產出一次,如果有別的地方也需要用到一樣的陣列的話,你複製過去用就好了。
String name = const '王小明';
//compile error, String 並沒有 constant 的建構子。
但是右側的 const 有個限制,他所標註的 value Type 必須有 constant 的 建構子,用以保證這個 value 是可以在編譯時就確認好了。
class Person{
final String name;
final int age;
const Person(this.name, this.age);
}void main(){
Person wang1 = const Person("王小明", 5);
Person wang2 = const Person("王小明", 5);
print(wang1 == wang2); //true
}
並且該 class 的 parameters 必須是 final,用以確保這個物件的值不會再被改動。
重點整理
- final 跟 在等號左側的 const 不同在於『時機點』。
- const 在等號左側修飾 Variables。
- const 在等號右側修飾 Value。
- const 都是為了告訴編譯器他所修飾的對象都不會再改變。