Dartのジェネリクスは共変
タイトルでオチがついている。Dartのジェネリクスって共変なんだねえ。
The Dart type system | Dart
https://dart.dev/guides/language/type-system#generic-type-assignment
共変とか知らんがな!わかりやすく説明せい!
あるクラスTsuperがサブクラスTsubをもつ場合に、Tsuperによる総称型にTsubによる総称型を代入できることを共変といいます
サブクラスとか知らんがな!もっとわかりやすく説明せい!
ジェネリクス型に互換性があるということを共変といいます
dartは互換性があるので共変です
dart
List<num> numList;
List<double> doubleList = [];
numList = doubleList; // 代入ができる。これが共変
一見この互換性は便利そうですが、以下のようなリスクがあります。
dart
List<num> numList;
List<double> doubleList = <double>[]; // [];の丁寧な書き方
numList = doubleList; // 代入ができる。これが共変(キリッ)
// コンパイルこそ通るものの、
// doubleで作ったリストにintをaddすることによって実行時エラーが発生する。
// 変数にnumListって書いてあるからいけそうなのにね。こわいねえ。
numList.add(2 as int); // 実行時エラー!
ちなみにJavaはジェネリクス型に互換性がありません(不変)1
java
List<Number> numberList;
List<Double> doubleList;
// numberList = doubleList; // コンパイルエラー
Flutterにおける身近な共変の利用
例えばこういう画面クラス。
dart
class MyPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return MyState();
}
}
class MyState extends State<MyPage> {
@override
Widget build(BuildContext context) {
return Scaffold(body: Text("this is view"));
}
}
MyPage.createState()の中身を冗長に書くとこういう風になります。
dart
class MyPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
State<StatefulWidget> returnValue;
State<MyPage> myState = MyState();
returnValue = myState; // 共変なので代入ができる
return returnValue;
}
}
class MyState extends State<MyPage> {
// (略)
}
-
この制約を緩めて使いやすくするためにextendsとかsuperとかワイルドカードとかの署名をこねくり回します(作る側は面倒くさい)。 ↩