內容

以下是建立變數並初始化的範例

dart
var name = 'Bob';

變數儲存參照。稱為 name 的變數包含對值為「Bob」的 String 物件的參照。

name 變數的類型會推論為 String,但您可以透過指定類型來變更該類型。如果物件不受限於單一類型,請指定 Object 類型(或必要時指定 dynamic)。

dart
Object name = 'Bob';

另一個選項是明確宣告會推論出的類型

dart
String name = 'Bob';

Null 安全

#

Dart 語言強制執行健全的 Null 安全性。

Null 安全性可防止因意外存取設定為 null 的變數而產生的錯誤。該錯誤稱為 Null 參考錯誤。當您存取評估為 null 的運算式中的屬性或呼叫方法時,就會發生 Null 參考錯誤。此規則的例外情況是當 null 支援該屬性或方法時,例如 toString()hashCode。有了 Null 安全性,Dart 編譯器會在編譯時偵測到這些潛在錯誤。

例如,假設您想要找出 int 變數 i 的絕對值。如果 inull,呼叫 i.abs() 會導致 Null 參考錯誤。在其他語言中,嘗試這麼做可能會導致執行時期錯誤,但 Dart 的編譯器禁止這些動作。因此,Dart 應用程式不會導致執行時期錯誤。

Null 安全性引入了三個主要變更

  1. 當您為變數、參數或其他相關元件指定類型時,您可以控制該類型是否允許 null。若要啟用可為 Null,請在類型宣告的結尾加上 ?

    dart
    String? name  // Nullable type. Can be `null` or string.
    
    String name   // Non-nullable type. Cannot be `null` but can be string.
  2. 您必須在使用變數之前初始化變數。可為 Null 的變數預設為 null,因此它們預設會初始化。Dart 沒有設定非可為 Null 類型的初始值。它會強制您設定初始值。Dart 不允許您觀察未初始化的變數。這可防止您存取屬性或呼叫方法,其中接收者的類型可以為 null,但 null 不支援所使用的屬性或方法。

  3. 您無法存取屬性或呼叫具有可為 Null 類型的運算式的屬性或方法。相同的例外情況適用於 null 支援的屬性或方法,例如 hashCodetoString()

健全的 Null 安全性會將潛在的執行時期錯誤轉換為編輯時期分析錯誤。當非可為 Null 變數已

  • 未初始化為非空值。
  • 指定為 null 值。

此檢查讓您在部署應用程式之前修正這些錯誤。

預設值

#

未初始化且具有可為空的型別的變數具有 null 的初始值。即使是數值型別的變數,其初始值也為 null,因為數字(與 Dart 中的其他所有內容一樣)都是物件。

dart
int? lineCount;
assert(lineCount == null);

使用 Null 安全性時,您必須在使用非可空變數之前初始化其值

dart
int lineCount = 0;

您不一定要在宣告區域變數時初始化它,但您需要在使用它之前指定一個值。例如,下列程式碼有效,因為 Dart 可以偵測到在傳遞給 print() 時,lineCount 為非 null

dart
int lineCount;

if (weLikeToCount) {
  lineCount = countLines();
} else {
  lineCount = 0;
}

print(lineCount);

頂層和類別變數會延遲初始化;初始化程式碼會在第一次使用變數時執行。

延遲變數

#

late 修改詞有兩個使用案例

  • 宣告在宣告後初始化的非可空變數。
  • 延遲初始化變數。

Dart 的控制流程分析通常可以偵測到在使用非可空變數之前,是否已將其設定為非 null 值,但有時分析會失敗。兩個常見的案例是頂層變數和實例變數:Dart 通常無法判斷它們是否已設定,因此不會嘗試。

如果您確定在使用變數之前已設定變數,但 Dart 不認同,您可以透過將變數標記為 late 來修正錯誤

dart
late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}

當您將變數標記為 late 但在宣告時初始化它時,初始化程式會在第一次使用變數時執行。這種延遲初始化在下列幾種情況下很方便

  • 變數可能不需要,而初始化它很昂貴。
  • 您正在初始化實例變數,而其初始化程式需要存取 this

在以下範例中,如果從未使用 temperature 變數,則永遠不會呼叫昂貴的 readThermometer() 函式

dart
// This is the program's only call to readThermometer().
late String temperature = readThermometer(); // Lazily initialized.

Final 和 const

#

如果您從未打算變更變數,請使用 finalconst,取代 var 或在型別之外使用。final 變數只能設定一次;const 變數是編譯時期常數。(Const 變數隱含為 final。)

以下是建立和設定 final 變數的範例

dart
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

您無法變更 final 變數的值

✗ 靜態分析:失敗Dart
name = 'Alice'; // Error: a final variable can only be set once.

對您希望成為編譯時期常數的變數使用 const。如果 const 變數位於類別層級,請將其標記為 static const。在您宣告變數時,將值設定為編譯時期常數,例如數字或字串文字、const 變數,或常數數字的算術運算結果

dart
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere

const 關鍵字不只用於宣告常數變數。您也可以使用它來建立常數,以及宣告建立常數值的建構函式。任何變數都可以有常數值。

dart
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`

您可以從 const 宣告的初始化表示式中省略 const,就像上面提到的 baz。如需詳細資訊,請參閱不要重複使用 const

您可以變更非 final、非 const 變數的值,即使它曾經有 const

dart
foo = [1, 2, 3]; // Was const []

您無法變更 const 變數的值

✗ 靜態分析:失敗Dart
baz = [42]; // Error: Constant variables can't be assigned a value.

您可以定義使用類型檢查和強制轉型isas)、集合 if展開運算子......?)的常數

dart
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if (i is int) i: 'int'}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; // ...and a spread.

如需有關使用 const 建立常數值的更多資訊,請參閱清單字典類別