LoginSignup
5
5

More than 5 years have passed since last update.

DartのオプショナルタイプとDart Editorの補完

Posted at

はじめに

Dartで同じオブジェクトに対して様々なメソッド呼び出しやプロパティアクセスをたくさんするときに便利なカスケード演算子での私のコメントが長かったので記事として独立させました。

実験

canvas.getContext('2d');

のようにスーパークラス型の関数が、実際にはサブクラスのオブジェクトを返すことがあります。
この場合にDart Editorによる補完がどのように働くか実験してみます。

class A {
  int a;
}

class B extends A {
  int b;
}

A fa(String t){
  if(t == 'A'){
    return new A();
  } else {
    return new B();
  }
}

void main() {
  var b1 = fa('B')..b = 1;        // (1)

  B   b2 = fa('B')..b = 2;        // (2)

  var b3 = fa('B') as B..b = 3;   // (3)

  B   b4 = fa('B');
  b4.b = 4;                       // (4)

  print('b1.b:${b1.b} b2.b=${b2.b} b3.b=${b3.b} b4.b=${b4.b}');
}
> b1.b:1 b2.b=2 b3.b=3 b4.b=4

解説

(1)のfa(’B')..のところで、メンバaとともにbもグレーアウトされた状態で最後の補完候補として現れます。
ここから、サブクラスのメンバは優先度を下げつつも候補としてリストする方針が見て取れます。

var b1dynamic型ですが、仮にこれを(2)のようにB b2に変更しても補完候補は変わりません。
fa('B')..の方がb2 =よりも先に評価されるため、変数b2の型情報Bが利用できないのでしょう。

文脈的にサブクラスのオブジェクトとわかっている場合はasを使ってキャストすると良いようです。
(3)の例ではas B..のところでaに続いてbがグレーアウトせずにリストされました。

なお、個人的には(3)を) as B..bと書いても、) as B ..bと書いてもスペースが気持ち悪いです。
加えてvarasが冗長なで、(4)の様に型情報は変数宣言に与えて、そのメンバ参照は文を分けたほうが素直だと思います。

ということで、(4)一択ですかね。

捕捉

  • (1)、(2)は動的には正しく、チェックドモードでも完走しますが、エディタやアナライザで警告が出るので非推奨です。
  • fa('B')fa('A')に変更しても補完動作は変わりませんが、当然ながら実行時エラーです。
  • Dartのキャストasは基本何もしません。メモリイメージを変更することもなければ、その動的解釈を変えることもありまえん。
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5