fuzzy study

仕事・趣味で勉強したことのメモ

Flutter開発の時に知っておくとよさそうなDart文法のメモ

Dart

DartはもともとJavaScriptを代替する目的で作られた言語で、何年も前からありますがあまり流行ってはいませんでした。 昨年、Dart2としてFlutterとともに話題再燃したようです。
私自身Dartに触れて一か月程度の身なのでまだよくわかっていないのですが、Dart2は個人的にかなり好きになりそうな言語です。

感触としてはこんな感じです。

Dartの今後に期待です。

以下、Dartの文法について、Flutter開発の時に知っておくとよさそうなもののメモ書きです。

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

ListView(
  children: <Widget>[
    Text("a"),
    Text("b"),
    Text("c"),
  ]
);

が普通のコンストラクタなのに対し、名前付きコンストラクタは

ListView.builder(
  itemBuilder: (context, index) => Text("$index")
);

のように、.のあとに名前を続け、いろいろな種類のインスタンスを返すコンストラクタを呼び分けられます。

Listにも

  • List.filled
  • List.from
  • List.generate

などの名前付きコンストラクタがあり、それぞれ異なった方法でリストを初期化できるようになっています。

よく使うのはList.generateで、

List.generate(10, (index) => "item $index");

のように、indexを引数とした関数の返す値に従って初期化されたListを返します。

関数の引数

普通に定義した関数では、引数の区別は位置で判断されます。

int add(int a, int b){
  return a + b;
}

add(1, 3); // 4

定義時に{}で括った引数はOptionalとなります。関数を呼ぶ際には位置ではなく名前で区別されるため、名前の指定が必須となります。

int add(int a, int b, {int c}){
  if(c == null){
    return a + b;
  }else{
    return a + b + c;
  }
}

add(1, 3); // 4
add(1, 3, c: 5); // 9
//add(1, 3, 5); // Error

名前つき引数に対する値の指定方法はコロン:区切りです。
変わってるな*1、と思いましたが、flutterのようにコンストラクタを多用する記法をしていると、 引数をコロン区切りで指定するのはJavaScriptでMap型(or Hash型 or dict型)を関数の引数に渡しているのと似たような記法となり、 むしろ意味合い的にわかりやすくなったように感じました。

(=で区切る場合、その値に無名関数を与えるときになんとなく不自然に感じるのは自分だけ?)

ちなみにOptional引数は、省略した際に使うデフォルト値を指定できます。 指定されていない引数について省略すると値はnullとなります。(明示的にnullをデフォルト値として指定すると警告が出る。)

int add(int a, int b, {int c: 100}){
  if(c == null){
    return a + b;
  }else{
    return a + b + c;
  }
}

add(1, 3); // 104
add(1, 3, c: 5); // 9

Listの生成

配列として使うList型ですが、Flutterでは各Widgetのコンストラクタの引数にListを指定したい場面が多くあります。
その場合、事前にfor文などでListを作るより、引数に渡すタイミングでListのオブジェクトを作るほうが良いケースもままあります。
そこで、Listを生成する方法を知っておくと役立ちます。

ちなみにListには固定長リストと可変長リストがあり、大抵のコンストラクタではgrowableパラメータにtrueを与えると可変長となります。 デフォルトでgrowableがtrueかfalseかはコンストラクタにより異なるので注意が必要です。
固定長リストに対してaddなどの要素追加や削除を伴うような操作を試みると、UnsupportedError例外が発生します。

// 空リスト(可変長)
var emptyList = List();
// または var emptyList = [];

// length指定(nullで初期化)(固定長)
var sizedList1 = List(3);

// length指定(nullで初期化)(可変長)
var sizedList2 = List()..length = 3;

// 同じ値で初期化(デフォルト固定長)
var list0 = List.filled(3, 1); // [1, 1, 1]
// list0.add(3); // UnsupportedError

// コピー(デフォルト可変長)
var list1 = List.from(list0); // [1, 1, 1]

// 関数を使って初期化(デフォルト可変長)
var list2 = List.generate(3, (i) => i * 2 + 1); // [1, 3, 5]

*1:Rubyも同様の記法のようですね。