變數
這是一個建立和初始化變數的示例
var name = 'Bob';變數儲存引用。名為 name 的變數包含對值為“Bob”的 String 物件的引用。
name 變數的型別被推斷為 String,但您可以透過明確指定來更改該型別。如果一個物件不限於單一型別,請指定 Object 型別(如果需要,也可指定 dynamic)。
Object name = 'Bob';另一種選擇是顯式宣告將被推斷的型別
String name = 'Bob';空安全
#Dart 語言強制執行健全的空安全。
空安全可防止因意外訪問設定為 null 的變數而導致的錯誤。此錯誤稱為空解引用錯誤。當您在評估為 null 的表示式上訪問屬性或呼叫方法時,會發生空解引用錯誤。此規則的例外情況是 null 支援該屬性或方法,例如 toString() 或 hashCode。透過空安全,Dart 編譯器在編譯時檢測這些潛在錯誤。
例如,假設您想查詢一個 int 變數 i 的絕對值。如果 i 為 null,則呼叫 i.abs() 會導致空解引用錯誤。在其他語言中,嘗試這樣做可能會導致執行時錯誤,但 Dart 的編譯器禁止這些操作。因此,Dart 應用程式不會導致執行時錯誤。
空安全引入了三個關鍵變更
當您為變數、引數或其他相關元件指定型別時,可以控制該型別是否允許
null。要啟用可空性,您需要在型別宣告的末尾新增一個?。dartString? name // Nullable type. Can be `null` or string. String name // Non-nullable type. Cannot be `null` but can be string.您必須在使用變數之前對其進行初始化。可空變數預設為
null,因此它們預設會被初始化。Dart 不為不可空型別設定初始值。它強制您設定初始值。Dart 不允許您觀察未初始化的變數。這可以防止您訪問接收者型別可能為null但null不支援所使用的方法或屬性的屬性或呼叫方法。您不能訪問可空型別表示式上的屬性或呼叫方法。同樣的例外也適用於
null支援的屬性或方法,例如hashCode或toString()。
健全的空安全將潛在的執行時錯誤轉化為編輯時分析錯誤。當不可空變量出現以下情況時,空安全會對其進行標記:
- 未用非空值初始化。
- 被賦予了
null值。
此檢查允許您在部署應用程式之前修復這些錯誤。
預設值
#具有可空型別的未初始化變數的初始值為 null。即使是數字型別的變數最初也是空值,因為數字(像 Dart 中的所有其他事物一樣)都是物件。
int? lineCount;
assert(lineCount == null);使用空安全時,您必須在使用不可空變數之前初始化其值
int lineCount = 0;您不必在宣告區域性變數時就對其進行初始化,但您需要在其使用之前為其賦值。例如,以下程式碼是有效的,因為 Dart 可以檢測到 lineCount 在傳遞給 print() 時是非空的
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
print(lineCount);頂層變數和類變數是延遲初始化的;初始化程式碼在變數首次使用時執行。
Late 變數
#late 修飾符有兩種用例
- 宣告一個在聲明後初始化的不可空變數。
- 延遲初始化變數。
通常,Dart 的控制流分析可以檢測到不可空變數在使用前何時被設定為非空值,但有時分析會失敗。兩種常見情況是頂層變數和例項變數:Dart 通常無法確定它們是否已設定,因此它不會嘗試。
如果您確定變數在使用前已設定,但 Dart 不同意,則可以透過將變數標記為 late 來修復該錯誤
late String description;
void main() {
description = 'Feijoada!';
print(description);
}當您將變數標記為 late 但在宣告時對其進行初始化時,初始化器會在變數首次使用時執行。這種延遲初始化在以下幾種情況下非常方便
- 變數可能不需要,並且初始化它成本很高。
- 您正在初始化一個例項變數,並且其初始化器需要訪問
this。
在以下示例中,如果 temperature 變數從未使用過,那麼開銷大的 readThermometer() 函式將永遠不會被呼叫
// This is the program's only call to readThermometer().
late String temperature = readThermometer(); // Lazily initialized.Final 和 const
#如果您不打算更改變數,請使用 final 或 const,可以替代 var,也可以與型別一起使用。final 變數只能設定一次;const 變數是編譯時常量。(const 變數隱式為 final。)
這是一個建立和設定 final 變數的示例
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';您不能更改 final 變數的值
name = 'Alice'; // Error: a final variable can only be set once.對您希望成為編譯時常量的變數使用 const。如果 const 變數在類級別,請將其標記為 static const。在宣告變數的地方,將其值設定為編譯時常量,例如數字或字串字面量、const 變數,或常量數字上的算術運算結果
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphereconst 關鍵字不僅用於宣告常量變數。您還可以用它來建立常量值,以及宣告建立常量值的建構函式。任何變數都可以擁有常量值。
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`您可以從 const 宣告的初始化表示式中省略 const,如上面 baz 所示。有關詳細資訊,請參閱 不要冗餘使用 const。
您可以更改非 final、非 const 變數的引用,即使它曾經具有 const 值
foo = [1, 2, 3]; // Was const []您不能更改 const 變數的值
baz = [42]; // Error: Constant variables can't be assigned a value.您可以定義使用型別檢查和轉換(is 和 as)、集合 if 和展開運算子(... 和 ...?)的常量
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 建立常量值的更多資訊,請參閱列表、對映和類。
萬用字元變數
#名稱為 _ 的萬用字元變數聲明瞭一個非繫結的區域性變數或引數;本質上,它是一個佔位符。如果存在初始化器,它仍會執行,但值不可訪問。在同一名稱空間中可以存在多個名為 _ 的宣告,而不會發生命名衝突錯誤。
頂層宣告或可能影響庫隱私的成員不適用於萬用字元變數。塊範圍內的區域性宣告,例如以下示例,可以宣告萬用字元
區域性變數宣告。
dartmain() { var _ = 1; int _ = 2; }for 迴圈變數宣告。
dartfor (var _ in list) {}catch 子句引數。
darttry { throw '!'; } catch (_) { print('oops'); }泛型和函式型別引數。
dartclass T<_> {} void genericFunction<_>() {} takeGenericCallback(<_>() => true);函式引數。
dartFoo(_, this._, super._, void _()) {} list.where((_) => true); void f(void g(int _, bool _)) {} typedef T = void Function(String _, String _);