目次

用語集

以下は、Dartドキュメント全体で使用される用語の定義です。

アシスト

#

アシストとは、コードに一般的な改善を加えることを目的とした自動化されたローカルコード編集です。アシストの例としては、switchステートメントをswitch式に変換したり、ifステートメントのthenブロックとelseブロックを反転したり、ウィジェット構造にウィジェットを挿入したりすることが挙げられます。

関連ドキュメントとリソース

定数コンテキスト

#

定数コンテキストとは、その領域内のすべてが定数である必要があるという事実によって暗黙のうちに示唆されるため、constキーワードを含める必要がないコード領域です。次の場所は定数コンテキストです。

  • constキーワードでプレフィックスされたリスト、マップ、またはセットリテラルの内側にあるすべて。例えば

    dart
    var l = const [/*constant context*/];
  • 定数コンストラクタの呼び出し内の引数。例えば

    dart
    var p = const Point(/*constant context*/);
  • constキーワードでプレフィックスされた変数の初期化子。例えば

    dart
    const v = /*constant context*/;
  • 注釈。

  • case句の式。例えば

    dart
    void f(int e) {
      switch (e) {
        case /*constant context*/:
          break;
      }
    }

関連ドキュメントとリソース

確定代入

#

確定代入分析は、コード内の各ポイントで各ローカル変数について、次のいずれが当てはまるかを判断するプロセスです。

  • 変数が確実に値が代入されている(確定代入)。
  • 変数が確実に値が代入されていない(確定未代入)。
  • 変数に値が代入されているかどうかは、そのポイントに到達するための実行パスによって異なる可能性がある。

確定代入分析は、値が代入されていない可能性のある変数が参照されている場所や、1回しか値を代入できない変数に値が既に代入されている可能性がある後に値を代入している場所など、コード内の問題を見つけるのに役立ちます。

例えば、次のコードでは、変数sは、printの引数として渡されるときに、確実に未代入です。

dart
void f() {
  String s;
  print(s);
}

しかし、次のコードでは、変数sは確実に代入されています。

dart
void f(String name) {
  String s = 'Hello $name!';
  print(s);
}

確定代入分析は、複数の実行パスがある場合でも、変数が確実に代入されている(または未代入)かどうかを判断できます。次のコードでは、ifステートメントのtrueまたはfalseのいずれかのブランチを実行した場合にprint関数が呼び出されますが、どちらのブランチが実行されてもsには値が代入されるため、printに渡される前に確実に代入されています。

dart
void f(String name, bool casual) {
  String s;
  if (casual) {
    s = 'Hi $name!';
  } else {
    s = 'Hello $name!';
  }
  print(s);
}

フロー分析では、ifステートメントの終わりは、2つ以上の実行パスが再びマージされる場所である結合と呼ばれます。結合がある場合、分析では、変数がマージするすべてのパスに沿って確実に代入されている場合は確実に代入され、すべてのパスに沿って確実に未代入の場合は確実に未代入であると言います。

変数が1つのパスで値を代入され、別のパスで値を代入されない場合、変数は値を代入されている場合もあれば、代入されていない場合もあります。次の例では、ifステートメントのtrueブランチが実行されるかどうかわからないため、変数は値を代入される場合もあれば、代入されない場合もあります。

dart
void f(String name, bool casual) {
  String s;
  if (casual) {
    s = 'Hi $name!';
  }
  print(s);
}

falseブランチでsに値を代入しない場合も同様です。

ループの分析はもう少し複雑ですが、基本的には同じ推論に従います。例えば、whileループの条件は常に実行されますが、本体は実行される場合もあれば、実行されない場合もあります。したがって、ifステートメントと同様に、whileステートメントの終わりには、条件がtrueの場合のパスと条件がfalseの場合のパスの間の結合があります。

関連ドキュメントとリソース

関数

#

トップレベル関数、ローカル関数、静的メソッド、およびインスタンスメソッドを指す包括的な用語。

関連ドキュメントとリソース

反駁不能なパターン

#

反駁不能なパターンとは、常に一致するパターンです。反駁不能なパターンは、反駁不能なコンテキストである、宣言および代入パターンコンテキストにのみ表示できるパターンです。

関連ドキュメントとリソース

ミックスイン適用

#

ミックスイン適用とは、ミックスインがクラスに適用されたときに作成されるクラスです。例えば、次の宣言を考えてみましょう。

dart
class A {}

mixin M {}

class B extends A with M {}

クラスBは、MAに適用したミックスイン適用のサブクラスであり、A+Mと命名されることもあります。クラスA+MAのサブクラスであり、Mからコピーされたメンバーを持ちます。

ミックスイン適用に実際の名前を付けるには、次のように定義します。

dart
class A {}

mixin M {}

class A_M = A with M;

A_Mのこの宣言を考えると、次のBの宣言は、元の例のBの宣言と同等です。

dart
class B extends A_M {}

関連ドキュメントとリソース

オーバーライド推論

#

オーバーライド推論とは、メソッド宣言で欠落している型が、オーバーライドするメソッドまたはメソッドからの対応する型に基づいて推論されるプロセスです。

候補メソッド(型情報が欠落しているメソッド)が単一の継承されたメソッドをオーバーライドする場合、オーバーライドされたメソッドからの対応する型が推論されます。例えば、次のコードを考えてみましょう。

dart
class A {
  int m(String s) => 0;
}

class B extends A {
  @override
  m(s) => 1;
}

Bmの宣言は、戻り値の型とパラメータ型の両方が欠落しているため、候補です。単一のメソッド(Aのメソッドm)をオーバーライドするため、オーバーライドされたメソッドの型を使用して欠落している型を推論し、Bのメソッドがint m(String s) => 1;として宣言されたかのように動作します。

候補メソッドが複数のメソッドをオーバーライドし、オーバーライドされたメソッドの1つであるMsの関数型が、他のすべてのオーバーライドされたメソッドの関数型のスーパータイプである場合、Msを使用して欠落している型を推論します。例えば、次のコードを考えてみましょう。

dart
class A {
  int m(num n) => 0;
}

class B {
  num m(int i) => 0;
}

class C implements A, B {
  @override
  m(n) => 1;
}

Cmの宣言は、戻り値の型とパラメータ型の両方が欠落しているため、オーバーライド推論の候補です。AmBmの両方をオーバーライドするため、コンパイラーは欠落している型を推論できる型をいずれか1つ選択する必要があります。しかし、Amの関数型(int Function(num))がBmの関数型(num Function(int))のスーパータイプであるため、Aの関数を使用して欠落している型を推論します。結果は、Cのメソッドをint m(num n) => 1;として宣言するのと同じです。

オーバーライドされたメソッドのいずれにも、他のすべてのオーバーライドされたメソッドのスーパータイプである関数型がない場合はエラーです。

関連ドキュメントとリソース

パートファイル

#

パートファイルとは、part ofディレクティブを含み、partディレクティブを使用してライブラリに含まれるDartソースファイルです。

関連ドキュメントとリソース

潜在的にnull許容

#

型が潜在的に非null許容であるとは、明示的に非null許容であるか、型パラメーターであるかのいずれかの場合を指します。

型が明示的に非null許容であるとは、疑問符(?)が後に続かない型名である場合を指します。ただし、Nulldynamicなど、常にnull許容となるいくつかの型があることに注意してください。また、FutureOrは、疑問符が後に続かないかつ型引数が非null許容である場合(例: FutureOr<String>)にのみ、非null許容となります。

型パラメーターは、実際のランタイム型(型引数として指定された型)が非null許容である可能性があるため、潜在的に非null許容です。たとえば、class C<T> {}という宣言が与えられた場合、型Cは、C<int>のように非null許容の型引数で使用できます。

関連ドキュメントとリソース

パブリックライブラリ

#

パブリックライブラリとは、パッケージのlibディレクトリ内にあり、lib/srcディレクトリ内にはないライブラリのことです。

関連ドキュメントとリソース

クイックフィックス

#

特定の診断によって報告された問題を修正することを目的とした、自動化されたローカルコード編集。

関連ドキュメントとリソース

リファクタリング

#

リファクタリングとは、非ローカルな変更や、ユーザーの操作を必要とする変更を目的としたコード編集です。リファクタリングの例としては、名前の変更、コードの削除、抽出などがあります。

関連ドキュメントとリソース

反駁可能なパターン

#

反駁可能パターンとは、パターンが値と一致するかどうかを判断するために、値に対してテストできるパターンのことです。一致しない場合、パターンは一致を反駁または否定します。反駁可能パターンは、マッチングコンテキストに現れます。

関連ドキュメントとリソース

サブクラス

#

サブクラスとは、extendsキーワードを使用するか、mixinの適用によって、別のクラスの実装を継承するクラスのことです。

dart
// A is a subclass of B; B is the superclass of A.
class A extends B {}

// B1 has the superclass `A with M`, which has the superclass A.
class B1 extends A with M {}

サブクラス関係は、関連するサブタイプ関係も暗示します。たとえば、class Aは、クラスAのインスタンスが属する関連型Aを暗黙的に定義します。したがって、class A extends Bは、クラスABのサブクラスであると宣言するだけでなく、Aが型Bサブタイプであることも確立します。

サブクラス関係は、サブタイプ関係のサブセットです。ドキュメントで「STのサブタイプでなければなりません」と書かれている場合、STのサブクラスであることは問題ありません。ただし、その逆は真ではありません。すべてのサブタイプがサブクラスであるわけではありません。

関連ドキュメントとリソース

サブタイプ

#

サブタイプ関係とは、ある型の値が、別の型であるスーパータイプの値が期待される場所で、代替可能である関係のことです。たとえば、STのサブタイプである場合、型Tの値が期待される場所に、型Sの値を代入できます。

サブタイプは、スーパータイプのすべての操作(および場合によっては追加の操作)をサポートします。実際には、これは、サブタイプの値をスーパータイプを期待する任意の場所に代入でき、スーパータイプのすべてのメソッドがサブタイプで利用できることを意味します。

これは少なくとも静的には当てはまります。特定のAPIは、その操作によっては、実行時に代入を許可しない場合があります。

一部のサブタイプ関係は、null許容型(たとえば、intint?のサブタイプ)や関数型(たとえば、String Function()void Function()のサブタイプ)のように、型の構造に基づいています。

サブタイプは、実装または継承(直接または間接)によってクラスに対して導入することもできます。

dart
// A is a subtype of B, but NOT a subclass of B.
class A implements B {}

// C is a subtype AND a subclass of D.
class C extends D {}

関連ドキュメントとリソース

共変性および変性の位置

#

クラス(またはmixinなどの他の型宣言)の型パラメーターは、型全体が実際の型引数とともに「共変」する場合、共変であると言われます。言い換えれば、型引数がサブタイプに置き換えられると、型全体もサブタイプになります。

たとえば、クラスListの型パラメーターは、リスト型が型引数とともに共変するため、共変です。intObjectのサブタイプであるため、List<int>List<Object>のサブタイプです。

Dartでは、すべてのクラス、mixin、mixinクラス、および列挙型の宣言のすべての型パラメーターは共変です。

ただし、関数型は異なります。関数型は、その戻り値の型では共変ですが、パラメーター型では反対(反変として知られる)です。たとえば、型int Function(int)は型Object Function(int)のサブタイプですが、int Function(Object)のスーパータイプです。

これは、その代替可能性を考慮すると理にかなっています。静的型がint Function(int)である関数を呼び出す場合、その関数は実際には実行時に型int Function(Object)である可能性があります。静的型に基づいて、intをそれに渡せることを期待します。関数は実際には任意のObjectを受け入れるため、これは問題ありません。これには、型intのすべてのオブジェクトが含まれます。同様に、返される結果は型intになります。これも、静的型に基づいて期待されるものです。

したがって、int Function(Object)int Function(int)のサブタイプです。

パラメーター型ではすべてが逆になることに注意してください。特に、関数型間のこのサブタイプ関係では、パラメーター型に対して反対のサブタイプ関係が存在する必要があります。たとえば、intObjectのサブタイプであるため、void Function(Object)void Function(int)のサブタイプです。

List<void Function(int)>のようなより複雑な型の場合、型の位置を考慮する必要があります。これを実現するには、型のパーツの1つをプレースホルダーに変えて、その位置に異なる型を配置したときに型に何が起こるかを検討します。

たとえば、プレースホルダー_の代わりに異なる型を配置できる型のテンプレートとして、List<void Function(_)>を考えてみましょう。この型は、そのプレースホルダーが発生する位置では反変です。

以下は、_の代わりにObjectintを代入することで、これを説明しています。void Function(Object)void Function(int)のサブタイプであり、voidvoidのサブタイプ(戻り値の型)であり、intObjectのサブタイプ(パラメーター型、逆順)であるため、List<void Function(Object)>List<void Function(int)>のサブタイプです。したがって、_の型は、型List<void Function(_)>全体とは反対の方向に変化します。そして、この「反対方向」は、定義により、それを反変位置にします。

共変位置も同様に定義されます。たとえば、_は型List<_>の共変位置にあり、_は型_ Function(int)の共変位置にもあります。

不変として知られる別の種類の位置もありますが、発生頻度がはるかに低いため、詳細はここでは省略します。

実際には、クラス、mixinなどの型引数が共変位置にあり、関数型の戻り値の型も共変位置にあるが、パラメーター型は反変位置にあることを知っておけば十分な場合がよくあります。

関連ドキュメントとリソース