【超初心者向け】Flutter/Dartのconstコンストラクタを持つMyAppウィジェットの定義について
Flutter/Dartのコードを学び始めると、
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
・・・・
}
というようなコードが頻繁に出てきますが、
この、たった2行に含まれる情報量の多さに愕然とすることでしょう(私のこと)
ということで、今回は、先ほどのコードが
それぞれどんな意味なのか、まとめていきたいと思います。
このコード、一言でまとめると?
「constコンストラクタを持つMyAppウィジェットの定義」
ということになるかと思います。
このコードの意味合いについて、詳しく見ていきましょう。
class MyApp extends StatelessWidgetという記述
extends StatelessWidget は、MyApp クラスが StatelessWidget クラスを継承(拡張)していることを意味します。
Flutterでは、UI要素はすべて「ウィジェット」として実装され、大きく2つのタイプに分けられます:
-
StatelessWidget(ステートレスウィジェット):
- 状態を持たない、つまり一度構築されると内部データが変化しないウィジェット
- 同じ入力(パラメータ)に対して常に同じ出力(表示)を生成する
- 画面の再描画が必要な場合は、新しいインスタンスが作成される
- 静的なUI要素(ラベル、アイコン、固定レイアウトなど)に適している
-
StatefulWidget(ステートフルウィジェット):
- 内部状態を持ち、その状態に応じて表示が変化するウィジェット
- ユーザー操作などに応じて動的に変化するUI要素に使用される
MyApp が StatelessWidget を継承するということは、アプリのルート構造が基本的に静的で、内部状態を持たないことを意味します。これは多くのFlutterアプリで標準的なアプローチです。
const MyApp({Key? key}) : super(key: key);という記述
概要
-
constが付いているので、「コンパイル時定数」として使える「こともある」コンストラクタ -
MyAppと記述しているので、コンストラクタの定義を示している -
MyAppの引数は{Key? key}である -
{}で囲まれているので、Key型のkeyは「名前付き引数」である - 「名前付き引数」、かつ、
requiredキーワードがないので、引数のkeyはあってもなくてもよい -
?がついているのでnullも受け付け可能 - 親クラスの
superの引数keyには、受け取ったkeyをそのまま渡している
補足
「コンパイル時定数」とは?
コンパイル時定数(コンパイル定数)は、プログラムのコンパイル時に値が確定する変数やオブジェクトであり、実行時のパフォーマンスを大きく向上させることができます。DartやFlutterのようなフレームワークでは重要な最適化手法です。
「コンパイル時定数」として「使えることもある」し「使えないこともある」
const が付いているコンストラクタは以下の条件がすべて満たされた場合のみ、コンパイル時定数として使用できます。
- コンストラクタに渡されるすべての引数が
constであること - クラスのすべてのインスタンス変数が
finalであること - クラスにコンストラクタ以外の処理(例えば計算など)が含まれていないこと
イニシャライザリスト: : super(key: key);
- コロン
:の後に書かれるsuper(key: key)が親クラスのコンストラクタを呼び出す部分 -
superは親クラス(StatelessWidget)のコンストラクタを参照しています -
(key: key)の部分で、左側のkey:は親クラスのコンストラクタの引数名、右側のkeyは自分(MyApp)が受け取った変数を指しています - この部分で「そのまま渡す」動作を実現しています
この2つの部分が組み合わさることで、MyAppインスタンス作成時に渡されたkeyが、StatelessWidgetクラスのコンストラクタにも同じ値で渡される仕組みが実現されています。
const MyApp({super.key})は同じ意味
const MyApp({super.key});
これは Dart 2.17 で導入された新しい短縮構文です。
const MyApp({super.key}) の構文では、実際は親クラス(StatelessWidget など)のコンストラクタの定義に従って型が決まります。
MyAppが継承しているの基本ウィジェットクラスである StatelessWidget(および StatefulWidget)のコンストラクタは
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key? key }) : super(key: key);
// ...
}
というように、Key? を使用して定義されています。
このように、親クラス側で Key? として(nullを許容する型として)定義されているため、super.key 構文を使うと自動的にこの型定義が引き継がれます。つまり、明示的に Key? と書かなくても、親クラスの型定義に従って null 許容になります。
新しい構文は、特に継承を使ったクラスでコードの繰り返しを減らすために導入されました。
基本的な機能は同じで、シンプルになっただけです。
なお、最新の Flutter プロジェクトでは、
この新しい短縮構文を使用することが推奨されています。
Discussion