2020/1/8 Dart クラス、Initializer list

(コンストラクタやメソッドの代わりに)クラス宣言内でインスタンス変数(プロパティ)を初期化した場合、インスタンス生成時に値がセットされます。それはコンストラクタやイニシャライザリストが実行される前です。

Constructors

クラス宣言内で、クラス名と同名の関数を作ることでコンストラクタを宣言します。(さらにNamed constructorを作ることもできます。)もっとも一般的な形式のコンストラクタは、generative constructorです。generative constructorはクラスの新しいインスタンスを生成します。

sample0-1

class Point {
  num x, y;

  Point(num x, num y) {
    // この方法が基本ですが、もっと良い方法をsample0-2に示します。
    this.x = x;
    this.y = y;
  }
}

thisキーワードは現在のインスタンスを参照します。

NOTE

thisキーワードは、「クラスのプロパティ名」と「コンストラクタの引数名」が同名の場合に使用します。そうでない場合thisは省略できますし、省略するのが普通です。


Dartでは、コンストラクタの引数で受け取った値をインスタンス変数に代入するパターンをもっとシンプルに記述することができます。(sample0-2)

sample0-2

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

Default constructors

コンストラクタを宣言しない場合、自動的にdefault constructorが用意されます。default constructorは引数がありません。そしてdefault constructorはスーパークラスの引数無しコンストラクタを実行します。

Constructors aren’t inherited

サブクラスはスーパークラスのコンストラクタを継承しません。コンストラクタを宣言していないサブクラスは、default constructor(引数無し、名前無し)のみを持っています。

 

 

 

 

 


まず普通のクラス定義、コンストラクタ定義(sample1-1)

sample1-1

void main(){
  Cont cont1=Cont('int_list_test11','int_list_test22');
  print(cont1.str1);
  print(cont1.str2);
}

class Cont{
  String str1;
  String str2;
  
  Cont(String s1,String s2){
    this.str1=s1;
    this.str2=s2;
    print('Using Constructor');
  }
}

//Using Constructor
//int_list_test11
//int_list_test22

コンストラクタの書き方を少し変えて、イニシャライザリストを使用した書き方もできる、という話。(sampel1-2)

sample1-2

void main(){
  Cont cont1=Cont('int_list_test11','int_list_test22');
  print(cont1.str1);
  print(cont1.str2);
}

class Cont{
  String str1;
  String str2;
  
  Cont(String s1,String s2):str1=s1,str2=s2{
    print('using intializer list');
  }
}

//using intializer list
//int_list_test11
//int_list_test22

イニシャライザリストの記述法

クラス名(引数部分) : イニシャライザリスト{

//コンストラクタ本体

}

赤文字部分がイニシャライザリスト。sample1-1とsample1-2、結果は同じです。

結果が同じならイニシャライザリスト使う必要ないじゃん、という感じですが、使う必要性はsample1-3で。


sample1-3

void main(){
  NumberedCont numcont1=NumberedCont(0);
  print('''
  numcont1.str1 :  ${numcont1.str1},
  numcont1.str2 :  ${numcont1.str2},
  number        :  ${numcont1.number}
  ''');
  
}

class Cont{
  String str1;
  String str2;
  
  Cont(String s1,String s2){
    this.str1=s1;
    this.str2=s2;
    print('Using Constructor of Cont');
  }
}

class NumberedCont extends Cont{
  num number;
  
  NumberedCont(num n):super('test1','test2'){
    print('Using Constructor of NumberedCont');
    this.number=n;
    
  }
}

Using Constructor of Cont
Using Constructor of NumberedCont
  numcont1.str1 :  test1,
  numcont1.str2 :  test2,
  number        :  0

Dartではスーパークラスのコンストラクタが引数無しの場合、サブクラスのインスタンス生成時、サブクラスのコンストラクタが実行される直前に勝手にスーパークラスのコンストラクタを呼び出します。

しかしスーパークラスのコンストラクタが引数有りの場合、スーパークラスのコンストラクタは勝手には呼び出されないので、手動で呼び出す必要がある(スーパークラスのコンストラクタを呼び出すコードを記述する必要がある)、ということです。その際、イニシャライザリストに記述しないといけない、ということのようです。多分サブクラスコンストラクタ実行の前にスーパークラスコンストラクタを実行させる必要があるため、ということだと思います。決まり文句みたいなことですかね。

上記に従って書いたサンプルコードがsample1-3。スーパークラスContのコンストラクタが、サブクラスNumberedContのコンストラクタより前に実行されています。

あと、インスタンス変数がfinalで宣言されている、つまりインスタンス定数ということですが。その際にインスタンス定数を初期化するのにイニシャライザリストが使える、ということもあるようです。

 

 

 

参考

https://dart.dev/guides/language/language-tour#constructors

コメントを残す

メールアドレスが公開されることはありません。