目次

変数

変数の作成と初期化の例を次に示します。

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`に評価される式に対してプロパティにアクセスしたり、メソッドを呼び出したりしたときに発生します。この規則の例外は、`toString()`や`hashCode`のように`null`がプロパティまたはメソッドをサポートする場合です。Nullセーフティを使用すると、Dartコンパイラはこれらの潜在的なエラーをコンパイル時に検出します。

たとえば、`int`変数`i`の絶対値を求めたいとします。`i`が`null`の場合、`i.abs()`を呼び出すとNull参照エラーが発生します。他の言語では、これを実行しようとするとランタイムエラーが発生する可能性がありますが、Dartのコンパイラはこれらのアクションを禁止します。そのため、Dartアプリはランタイムエラーを引き起こすことがありません。

Nullセーフティは、3つの重要な変更を導入します。

  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許容型の式に対してプロパティにアクセスしたり、メソッドを呼び出したりすることはできません。`hashCode`や`toString()`のように`null`がサポートするプロパティまたはメソッドの場合も、同じ例外が適用されます。

サウンドなNullセーフティは、潜在的な**ランタイムエラー**を**編集時**の解析エラーに変換します。Nullセーフティは、Null非許容変数が次のいずれかの場合にフラグを立てます。

  • Null以外の値で初期化されていない。
  • `null`値が割り当てられている。

このチェックにより、アプリをデプロイする前にこれらのエラーを修正できます。

デフォルト値

#

Null許容型の初期化されていない変数は、`null`の初期値を持ちます。数値型を持つ変数でさえ、最初はnullになります。なぜなら、数字は—Dartの他のものと同様に—オブジェクトだからです。

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

Nullセーフティでは、Null非許容変数の値は、使用前に初期化する必要があります。

dart
int lineCount = 0;

宣言時にローカル変数を初期化する必要はありませんが、使用前に値を代入する必要があります。たとえば、次のコードは有効です。Dartは、`print()`に渡されるまでに`lineCount`がNullではないことを検出できるためです。

dart
int lineCount;

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

print(lineCount);

トップレベル変数とクラス変数は遅延初期化されます。初期化コードは、変数が初めて使用されたときに実行されます。

遅延変数

#

`late`修飾子には、2つのユースケースがあります。

  • 宣言後に初期化されるNull非許容変数を宣言する。
  • 変数を遅延初期化する。

多くの場合、Dartの制御フロー解析は、Null非許容変数が使用される前に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

#

変数を変更する予定がない場合は、`var`の代わりに、または型に加えて`final`または`const`を使用します。`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`キーワードは、定数変数の宣言のためだけではありません。`const`値の作成、および`const`値を作成するコンストラクタの宣言にも使用できます。任意の変数は、定数値を持つことができます。

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

上記の`baz`のように、`const`宣言の初期化式から`const`を省略できます。詳細はconstを冗長に使用しないを参照してください。

`final`ではない`const`ではない変数の値は、以前`const`値を持っていた場合でも変更できます。

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

`const`変数の値を変更することはできません。

✗ 静的解析:失敗dart
baz = [42]; // Error: Constant variables can't be assigned a value.

型チェックとキャスト(`is`と`as`)、コレクション`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`を使用して定数値を作成する方法の詳細については、リストマップクラスを参照してください。