2021/09/25

【flutter】コンストラクタについて説明回

@ 古曳 純基

Flutter

flutterのコンストラクタ種類多すぎるやろ...
そんなとき、めちゃくちゃわかりやすい記事に出会いました。
今回はその記事を参考に私の考えを整理していきたいと思います。

Generative Constructors(生成的コンストラクタ)

こちらは一般的なコンストラクタです。
new演算子を使うことでコンストラクタを起動することができます。
実際にコードを見てみましょう!
以下のコードがクラスの実装のコードです。引数を指定しないタイプのコンストラクタを実装します。

class Human {
  var name;
  Human(){
    this.name = "Anonymous";
  }
}


クラスからインスタンスを作成してみましょう!

// main関数の中でインスタンスを作成するコードを書いていく
main(){
  var human = new Human();
  print(human.name);
}


コンソール画面

Anonymous


引数を指定するタイプのコンストラクタを持つクラスを作成してみましょう!

void main() {
  // Humanクラスのコンストラクタの実行(引数に"Junki"を渡す)
  var human = new Human("Junki");
  print(human.name);
}
class Human {
  var name;
  Human(name){
    this.name = name;
  }
}


コンソール画面

Junki


以上が基本的なコンストラクタの実装になります。

Automatic field initialization(フィールドの自動初期化)

先程説明した引数を受け取るタイプのコンストラクタについてですが、引数で受け取った値をわざわざthis.nameに代入するようにコードを書く必要があります。これめんどくさいですよね...。
その問題を解決するのがAutomatic field initializationになります。
Constructor(this.fieldname)のように書くことで自動的にメンバ変数のnameに引数のnameの値を渡してくれます。便利〜。

実際のコードをいかに示します

void main() {
  // Humanクラスのコンストラクタの実行
  var human = new Human("Automatic man");
  print(human.name);
}
class Human {
  var name;
  // Automatic field initializationコンストラクタの定義
  Human(this.name);
}


コンソール画面

Automatic man


Named Constructors(名前付きコンストラクタ)

名前付きコンストラクタは、その名の通りコンストラクタに対して名前をつけることが可能です。
Constructors.name()のように書くことで実装することができます。
イメージとしては、コンストラクタをオーバーロードする感じです。
実際にコードを見てみましょう。

void main() {
  // Humanクラスのコンストラクタの実行
  var human = new Human();
  var junki = new Human.name("Junki");
  print(human.name);
  print(junki.name);
}
class Human {
  var name;
  // 一般的なコンストラクタ
  Human(){
    this.name = "Anonymous";
  }
  // 名前付きコンストラクタ
  Human.name(this.name);
}


コンソール画面

Anonymous
Junki


Redirecting Constructors(リダイレクティングコンストラクタ)

起動させるコンストラクタを指定することができる記述方法です。コンストラクタの後に:に続いて起動させたいコンストラクタを指定することができます。

void main() {
  // Humanクラスのコンストラクタの実行
  var human = new Human();
  var junki = new Human.name("Junki");
  print(human.name);
  print(junki.name);
}
class Human {
  var name;
  // リダイレクトする
  Human():this.anonymous();
  // 名前付きコンストラクタ(匿名版)
  Human.anonymous(){
    this.name = "Anonymous";
  }
  // 名前付きコンストラクタ
  Human.name(this.name);
}


コンソール画面

Anonymous
Junki


リダイレクト元のコンストラクタに処理を定義することが可能です(マージの挙動)。
この場合、リダイレクト先のコンストラクタが先に走って、その後リダイレクト元のコンストラクタが走るようです。
具体的なユースケースとして、クラス継承時に親クラスのコンストラクタをオーバーライドする際にリダイレクティングコンストラクタを使用すると思います。
実際にコードを見てみましょう。

// main関数(ビルド時に走る関数)
void main(){
  final junki = new Junki("junki",20);
  print("My name is " + junki.name);
  print(junki.age);
}

// 親クラスの定義
class Human {
  // member variable
  var name;
  // constructor
  Human(name) {
    this.name = name;
  }
}


// 継承クラスの定義
class Junki extends Human {
  var name;
  var age;
  // 親クラスのコンストラクタをリダイレクト
  Junki(name,age):super(name){
    this.age = age;
  }
} 


コンソール画面

My name is junki
20


Initializer Lists

コンストラクタの後に:に続けてフィールドの初期化処理を記述していくようです。
これで書くぐらいなら、普通のコンストラクタで書いたほうがわかりやすいのではないかと思いました。

実際にコードを見てみまましょう。

void main() {
  final human1 = new Human.initializerList("name1",1);
  print(human1.name);
  print(human1.age);


  print("---------------------------");
  final human2 = new Human.normal("name2",2);
  print(human2.name);
  print(human2.age);
}


class Human {
  // member variables
  var name;
  var age;
  
  // constructor(initializer lists)
  Human.initializerList(name,age): this.name = name,
           this.age = age;
  
  // normal constructor
  Human.normal(name,age) {
    this.name = name;
    this.age = age;
  }
}


コンソール画面

name1
1
---------------------------
name2
2


以下のように書くことでプロパティ初期化子のような機能を持たせることができます。

void main() {
  final human = new Human("banana");
  print(human.name);
  print(human.age);
  print(human.food);
  
}


class Human {
  // member variables
  var name;
  var age;
  var food;
  
  // constructor
  Human(this.food) : this.name = "Anonymous",
            this.age = 0;
}


コンソール画面

Anonymous
0
banana


最後に

おつです。
参考にした記事のリンクを以下に載せておきます。

Dartのコンストラクタについて | DevelopersIO
https://dev.classmethod.jp/articles/about_dart_constructors/
© 2021 powerd by UnReact