torikatsu.dev

Flutterとかプログラミングとかガジェットとか書きます

Dartのコンストラクタ紹介

こんばんは。最近Flutterでアプリ開発をしているとりかつです。

Dartにはコンストラクタが数種類あるのですが、Flutterをはじめたてのころ、けっこうつまづきました。

そこで今回の記事ではDartのコンストラクタの種類と使い方について紹介したいと思います。

Generative Constructor

ここでは生成的コンストラクタ(通常のコンストラクタ)を紹介していきます。

通常のコンストラク

Dartのコンストラクタはクラス名で宣言します。Javaを触ったことのある人には馴染みがあるかと思います。

class Sample {
  Sample(String text) {
    someField = text;
  }
  
  String someField;
}

フィールド代入の省略

これで動作はするのですが、もうひと工夫加えたいと思います。

Dartにはコンストラクタでのフィールド代入を省略する機能があります。

以下のようにコンストラクタの引数でthis.hogehogeとしてやるだけです。さらに、コンストラクタの処理がない時は{・・・}を省略することができます。

class Sample {
  Sample(this.someField);
  
  String someField;
}

簡単ですね。 こうするとコードの行数が減るだけでなく、変数名を考える手間も省けるので生産性が上がりそうです。

積極的につかっていきましょう。

ネームドコンストラク

Dartではコンストラクタのオーバーロードがサポートされていません。 その代わり、ネームドコンストラクがあります。

以下は色を表すクラスです。

class Color {
  Color.fromRGB(this.r, this.g, this.b) {
    alpha = 1.0;
  }

  Color.fromRGBA(this.r, this.g, this.b, this.a);

  /// red
  int r;

  /// green
  int g;

  /// blue
  int b;

  /// alpha
  double alpha;
}

このようにクラス名.コンストラクタ名で宣言できます。 これも簡単ですね。

ネームドコンストラクタをつかうことで、どうやってインスタンスを生成しているかが明確になります。

ネームドコンストラクタの命名にはfromキーワードを使うとインスタンス生成時のコードが自然言語ライクになるので個人的にオススメです。

/// fromを使わない場合
final color = Color.RGB(100, 20, 49);

/// fromを使った場合
final color = Color.fromRGB(100, 20, 49);

オプショナルパラメータを使えばもっとスマートに実装できますが、それについてはここでは触れないどきます。

定数コンストラク

Dartには定数コンストラクというものがあります。 以下は定数コンストラクタの例です。

class Sample{
  const Sample(this.text);
  
  final String text;
}

コンストラクタの先頭にconstがついているのがわかると思います。 これが定数コンストラクタです。

定数コンストラクタを使うことで、インスタンスの生成時にconstキーワードをつけて、定数オブジェクトをインスタンス化することができます。

 const Sample('サンプル');

定数コンストラクタを宣言する条件は以下の2つです。

  • クラスのフィールドが全てfinal
  • コンストラクタのボディがない(InitializerListはOK)

少し難しく感じますが、慣れてくるとなんてことはなくなります。

ユースケースとしてはパフォーマンスの向上が考えられます。

FlutterのStreamなんかがわかりやすいと思います。

以下のコードはStereamBuilderの例です。

StreamBuilder<String>(
  stream: textStream,
  builder: (context, snapshot) => Column(
    children: <Widget>[
      /// text widget A
      Text(snapshot.data),
      
      /// text widget B
      Text('サンプル'),
    ],
  ),
);

この場合、steramに値が流れてくるたびにtext widget Atext widget Bが更新されます。

text widget Bのコンストラクタの引数は'サンプル'という定数の文字列のため、constキーワードをつけて定数化することができます。

StreamBuilder<String>(
  stream: textStream,
  builder: (context, snapshot) => Column(
    children: <Widget>[
      /// text widget A
      Text(snapshot.data),
      
      /// text widget B
      const Text('サンプル'),
    ],
  ),
);

text widget Bは定数のため、streamに値が流れてきても再描画されるのはtext widget Aのみで済みます。

今回の例では、パフォーマンスへの影響はほとんどありませんが、「チリも積もれば山となる」ので、積極的に使っていきましょう。

終わりに

本当はファクトリコンストラクタまで紹介しようと思ったのですが、寝るのが遅くなってしまいそうなので、次回の記事で紹介したいと思います。

Dartでコンストラクタをつかいこなすことは可読性とパフォーマンスの向上に大きく貢献すると思うので、ぜひみなさんもコンストラクタとお友達になりましょう。