メインコンテンツにスキップ

変数

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

dart
var name = 'Bob';

変数は参照を格納します。name という名前の変数は、値が "Bob" の String オブジェクトへの参照を含んでいます。

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

dart
Object name = 'Bob';

もう 1 つのオプションは、推測される型を明示的に宣言することです。

dart
String name = 'Bob';

Null 安全性

#

Dart 言語は、健全な Null 安全性を強制します。

Null 安全性は、null に設定された変数への意図しないアクセスによって発生するエラーを防ぎます。このエラーは Null デリファレンス エラーと呼ばれます。Null デリファレンス エラーは、null に評価される式に対してプロパティにアクセスしたり、メソッドを呼び出したりすると発生します。この規則の例外は、nulltoString()hashCode のようにプロパティまたはメソッドをサポートしている場合です。Null 安全性により、Dart コンパイラはこれらの潜在的なエラーをコンパイル時に検出します。

たとえば、int 型の変数 i の絶対値を見つけたいとします。inull の場合、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 を持ちます。数値型を持つ変数でさえ、Dart ではすべてがオブジェクトであるため、最初は null です。

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

Null 安全性により、使用する前に非 Null 許容変数の値を初期化する必要があります。

dart
int lineCount = 0;

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

dart
int lineCount;

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

print(lineCount);

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

late 変数

#

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

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

多くの場合、Dart の制御フロー分析は、非 Null 許容変数が使用される前に非 Null 値に設定されていることを検出できますが、分析が失敗することもあります。一般的な 2 つのケースは、トップレベル変数とインスタンス変数です。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 は定数変数を宣言するためだけではありません。定数 **値** を作成するためにも使用でき、定数値を **作成する** コンストラクターを宣言するためにも使用できます。任意の変数に定数値を指定できます。

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

const 変数の初期化子の const を省略できます。たとえば、上記の baz のように。詳細については、冗長な const は使用しないでください を参照してください。

dart
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `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 を使用する方法の詳細については、リストマップ、および クラス を参照してください。

ワイルドカード変数

#

名前が _ のワイルドカード変数は、束縛のないローカル変数またはパラメーターを宣言します。実質的にはプレースホルダーです。初期化子がある場合でも実行されますが、値にはアクセスできません。名前が _ の複数の宣言を、競合エラーなしに同じ名前空間に存在させることができます。

ライブラリのプライバシーに影響を与える可能性のあるトップレベル宣言またはメンバーは、ワイルドカード変数の有効な使用ではありません。次の例のように、ブロック スコープにローカルな宣言は、ワイルドカードを宣言できます。

  • ローカル変数宣言。

    dart
    main() {
      var _ = 1;
      int _ = 2;
    }
  • for ループ変数宣言。

    dart
    for (var _ in list) {}
  • Catch 節のパラメーター。

    dart
    try {
      throw '!';
    } catch (_) {
      print('oops');
    }
  • ジェネリック型と関数型パラメーター。

    dart
    class T<_> {}
    void genericFunction<_>() {}
    
    takeGenericCallback(<_>() => true);
  • 関数パラメーター。

    dart
    Foo(_, this._, super._, void _()) {}
    
    list.where((_) => true);
    
    void f(void g(int _, bool _)) {}
    
    typedef T = void Function(String _, String _);