Skip to content

変数

変数の作成と初期化の例です:

dart
var name = 'Bob';

変数は参照を格納する。nameという変数には、"Bob"という値を持つStringオブジェクトへの参照が格納されている。

name変数の型はStringと推測されるが、型を指定することで変更できる。オブジェクトの型が1つに限定されない場合は、Object型(必要に応じてdynamic型)を指定する。

dart
Object name = 'Bob';

もう一つの方法は、推論される型を明示的に宣言することである:

dart
String name = 'Bob';

Note

このページでは、ローカル変数には型アノテーションではなくvarを使うというスタイルガイドの推奨に従っている。

Null safety

Dart言語では、ヌルの安全性を確保している。

ヌル・セーフティは、nullに設定された変数への意図しないアクセスによって発生するエラーを防ぎます。このエラーはヌル再参照エラーと呼ばれます。NULL参照解除エラーは、nullと評価される式のプロパティにアクセスしたりメソッドを呼び出したりすると発生します。このルールの例外は、toString()hashCodeのように、nullがプロパティやメソッドをサポートしている場合です。ヌル・セーフティでは、Dart コンパイラがコンパイル時にこれらの潜在的なエラーを検出します。

例えば、int型変数iの絶対値を求めたいとします。inullの場合、i.abs()を呼び出すとnullの再参照エラーが発生します。他の言語ではこれを試すと実行時エラーになる可能性がありますが、Dartのコンパイラはこのような動作を禁止しています。したがって、Dartアプリが実行時エラーを引き起こすことはありません。

Nullセーフティは、3つの重要な変更をもたらします:

  1. 変数、パラメータ、その他の関連コンポーネントに型を指定するとき、その型がnullを許すかどうかを制御することができます。 nullabilityを有効にするには、型宣言の最後に?を追加する。
dart
String? name  // Null可能な型。nullまたは文字列。

String name   // NULL不可の型。nullにはできないが、文字列にはできる。
  1. 変数を使用する前に初期化する必要があります。Nullable 変数のデフォルトは null なので、デフォルトで初期化されます。Dart は null値を持たない型に初期値を設定しません。初期値を設定するように強制されます。Dartでは、初期化されていない変数を観察することはできません。このため、受信者の型が null であっても、null が使用されるメソッドやプロパティをサポートしていない場合、プロパティにアクセスしたりメソッドを呼び出したりすることができません。

  2. null可能な型を持つ式のプロパティにアクセスしたり、メソッドを呼び出したりすることはできません。同じ例外が、hashCodetoString()のようにnullがサポートするプロパティやメソッドにも適用されます。

健全なヌル・セーフティは、潜在的な 実行時エラー編集時 の解析エラーに変える。ヌル・セーフティは、ヌルでない変数にフラグを立てる:

  • null以外の値で初期化されていない。
  • null値を代入。

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

デフォルト値

null可能な型を持つ初期化されていない変数の初期値はnullです。数値型の変数も初期値は NULL です。Dart の他のすべてのものと同様、数値もオブジェクトだからです。

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

Note

本番コードは assert() 呼び出しを無視する。一方、開発中のコードでは、assert(condition) は条件が false の場合に例外をスローします。詳細は Assertを参照ください。

ヌル・セーフティでは、ヌルでない変数の値は、使用する前に初期化しなければならない:

dart
int lineCount = 0;

ローカル変数は宣言された場所で初期化する必要はありませんが、使用する前に値を代入する必要があります。例えば、以下のコードは、lineCountprint()に渡されるまでにNULLでないことをDartが検出できるため、有効です:

dart
int lineCount;

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

print(lineCount);

トップレベル変数とクラス変数は遅延初期化される。初期化コードは、その変数が最初に使われたときに実行される。

late変数

late修飾子には2つの使用例がある:

  • 宣言後に初期化されるNULLでない変数の宣言。
  • 変数の初期化を怠る。

多くの場合、Dartの制御フロー解析は、非NULL変数が使用される前に非NULL値に設定されたことを検出できますが、解析に失敗することもあります。よくあるケースは、トップレベル変数とインスタンス変数です:Dartはこれらの変数が設定されているかどうかを判断できないことが多いため、試行しません。

変数が使用される前に設定されていることは確かだが、Dartがそれを認めない場合は、その変数をlateとしてマークすることでエラーを修正できる:

dart
late String description;

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

Notice

late変数の初期化に失敗すると、その変数が使用されるときに実行時エラーが発生する。

変数をlateとマークしておきながら宣言時に初期化すると、その変数が最初に使われるときにイニシャライザーが実行される。この遅延初期化は、いくつかの場合に便利である:

  • 変数が不要で、初期化にコストがかかる場合。
  • インスタンス変数を初期化していて、そのイニシャライザーがこの変数にアクセスする必要がある。

次の例では、もしtemperature変数が使われなければ、高価なreadThermometer()関数が呼ばれることはありません:

dart
// このプログラムでは、readThermometer()の呼び出しはこれだけである。
late String temperature = readThermometer(); // Lazily initialized.

final と const

変数を変更するつもりがない場合は、varの代わりに、あるいは型に加えて、finalまたはconstを使う。final変数は一度しか設定できないが、const変数はコンパイル時の定数である。∂const変数はコンパイル時の定数です(const変数は暗黙的にfinalとなります)。

Note

インスタンス変数はfinalにできるが、constにはできない。

以下は、final変数を作成して設定する例である:

dart
final name = 'Bob'; // 型注釈なし
final String nickname = 'Bobby';

final変数の値を変更することはできない:

✗ static analysis: failuredart

dart
name = 'Alice'; // エラー:final変数は一度しか設定できない。

コンパイル時に定数にしたい変数には const を使う。定数変数がクラス・レベルにある場合は、static const とします。変数を宣言する場所では、値を数値や文字列リテラル、const 変数、定数に対する算術演算の結果などのコンパイル時定数に設定します:

dart
const bar = 1000000; // 圧力の単位(dynes/cm2)
const double atm = 1.01325 * bar; // 標準大気

constキーワードは、定数変数を宣言するためだけのものではありません。定数値を作成するコンストラクタの宣言にも使用できます。どんな変数でも定数値を持つことができます。

dart
var foo = const [];
final bar = const [];
const baz = []; // `const []` に相当する。

上記のbazのように、const宣言の初期化式からconstを省略することができる。詳しくは、constを重複して使わないを参照してください。

finalでない、const でない変数の値を変更することができます:

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

const変数の値を変更することはできない:

✗ static analysis: failuredart

dart
baz = [42]; // エラー:定数変数に値を代入できません。

型チェックやキャスト(isやas)、コレクションif、スプレッド演算子(...や...?)を使用する定数を定義できます:

dart
const Object i = 3; // ここで、i は int 値を持つ const オブジェクトである。
const list = [i as int]; // タイプキャストを使う。
const map = {if (i is int) i: 'int'}; // 使用はis、回収はif。
const set = {if (list is List<int>) ...list}; // ...とスプレッド。

Note

finalオブジェクトは変更できませんが、そのフィールドは変更できます。これに対して、constオブジェクトとそのフィールドは変更できません。

constを使って定数値を作成する方法の詳細については、リスト、マップ、およびクラスを参照してください。