Flutterをやるにあたり、Dart全然わかってないのもあれだなということで、まずは基本的なところを写経。
目次
main関数
void main() { print("Hello World"); }
- 起動はvoid
main()
から - 行末はセミコロンが必要
コメント
// 1行コメント /* 複数行コメント */ void main() { print(/* こんな書き方もできるみたい */ 'Hello World'); }
- 1行は
//
、複数行は/* 〜 */
/* 〜 */
を途中に差し込むこともできるみたい
変数
void main() { var a = 1; var b = 2; var c = a + b; var d; var greeting = "Hello"; print(c); // 3 print(d); // null print("$greeting World"); // "Hello World" print("${greeting * 2} World"); // "HelloHelloHello World" }
var
で宣言した場合は型推論される- 宣言と同時に初期値を設定可
- 初期値を設定しない場合はnull
$
で変数の値を展開して埋め込める${ 〜 }
で{}
内の処理を展開して埋め込める
void main() { var a = 1; print(a); // 1 a = 2; print(a); // 2 a++; print(a); // 3 }
- 型が同じなら再代入も可能
型
void main() { int a = 1; int b = 2; int c = 0xFF; double d = 3.0; String e = "Hello"; String f = " World"; print(a); // 1 print(c); // 255 print(a + b); // 3 print(a + d); // 4.0 print(e); // "Hello" print(e + f); // "Hello World" }
- 型を指定して宣言
void main() { int a = 1; print(a); a = 2.0; print(a); }
- 型が異なる場合の再代入はエラー
sample.dart:4:7: Error: A value of type 'double' can't be assigned to a variable of type 'int'. a = 2.0; ^
int/double(数値)
void main() { int a = 1; int c = 0xFF; print(a); // 1 print(c); // 255 }
- 16進数は
0x
をつける
void main() { double a = 1.0; double b = 0.000314e4; double c = 31400e-4; int d = 3; print(a); // 1.0 print(b); // 3.14 print(c); // 3.14 print(d * a); // 3.0 }
- int * doubleで計算してキャストさせることも
String(文字列)
void main() { String a = "Hello"; String b = "World"; String c = """Hello World"""; String d = "${a} ${b}"; String e = '${a} ${b}'; print(a + " " + b); // "Hello World" print((a + " ") * 3 + b); // "Hello Hello Hello World" print(c); // "Hello // World" print(d); // "Hello World" print(e); // "Hello World" }
- UTF-16
- 改行を含む文字列はクオート3つ
- シングルクォートとダブルクォートの違いはないっぽい
- 文字列の計算も他の言語と同じ感じ
bool(真偽)
void main() { bool a = true; bool b = false; print(a); // true print(b); // false }
List(配列)
void main() { List<String> a = ["John", "Paul", "George", "Ringo"]; List<int> b = [2, 5, 4, 1, 3]; var c = ["a", "b", "c"]; print(a[0]); // "John" print(a[1]); // "Paul" print(a.last); // "Ringo" b.add(6); print(b); // [2, 5, 4, 1, 3, 6] b.insert(0, 0); print(b); // [0, 2, 5, 4, 1, 3, 6] b.sort((a,b) => a - b); print(b); // [0, 1, 2, 3, 4, 5, 6] a.forEach((i) => print(i)); // "John // Paul // George // Ringo" var d = b.map((i) => i * 2); var e = b.map((i) => i * 2).toList(); print("${b.runtimeType} : ${b}"); // List<int> : [0, 1, 2, 3, 4, 5, 6] print("${d.runtimeType} : ${d}"); // MappedListIterable<int, int> : (0, 2, 4, 6, 8, 10, 12) print("${e.runtimeType} : ${e}"); // List<int> : [0, 2, 4, 6, 8, 10, 12] }
- <>内に要素の型を指定する。指定せずに宣言も可能
- インデックス指定。-1は使えなかった。.lastメソッドとかlst.length-1をインデックスに指定したりするみたい。
- addとかmapとか。
- sortやforEach, mapはコールバックに渡す。mapでreturnするとListじゃなくてMappedListIterableになる。toList()してあげる。
Set(重複不可な配列)
void main() { Set<int> a = {1,2,3,4,5}; //a.add(1); // 重複するのでエラー a.add(6); print(a); // {1, 2, 3, 4, 5, 6} //print(a[0]); // リストじゃないのでインデックスで呼び出せない print((a.toList())[0]); // 1 (toListしてからインデックスで呼び出す) }
- 重複不可なリスト
- 順番がないのでインデックスで呼び出せない。toListすれば呼び出せる。多分用途が違う。
Map(マップ)
void main() { Map<String,String> a = { "Backing Guitar": "John", "Bass Guitar" : "Paul", "Lead Guitar" : "George", "Drum" : "Pete", }; print(a['Drum']); // "Pete" a.remove('Drum'); a["Drum"] = "Ringo"; Map<String,String> b = { "Manager": "Brian", "Producer": "Martin", }; a.addAll(b); a.forEach((k,v) => print("${k}: ${v}")); // => Backing Guitar: John // Bass Guitar: Paul // Lead Guitar: George // Drum: Ringo // Brian: Manager // Martin: Producer print(a.containsKey('Keyboard')); // false print(a.containsKey('Bass Guitar')); // true }
- キーと値に型が必要
- ネスト
kun432-mbp2016:dart_sandbox kun432$ cat eee void main() { Map<String,Map<String,String>> a = { // 多分ここの型指定がよくない。varとかで型推論させても同じ。 "Backing Guitar": { "Name": "John", }, "Bass Guitar" : { "Name": "Paul", }, "Lead Guitar" : { "Name": "George", }, "Drum" : { "Name": "Ringo", } }; print(a['Backing Guitar']['Name']); // Error: Operator '[]' cannot be called on 'Map<String, String>?' because it is potentially null. }
void main() { dynamic a = { // dynamicを使うとOK。`Map<String,dynamic>`でもOK。これが正しいのかはわからない。 "Backing Guitar": { "Name": "John", }, "Bass Guitar" : { "Name": "Paul", }, "Lead Guitar" : { "Name": "George", }, "Drum" : { "Name": "Ringo", } }; print(a['Backing Guitar']['Name']); // "John" }
- dynamicは途中で型が変わっても良い、varは初期化時に型が決まるので以降は違う型を入れれない、らしい。
- 多分そういうことじゃなくて、わかってないだけ。これぐらいのものならもっときちんと型定義できる気がする・・・
定数
void main() { final int a = 1; // a = 2; // => Error: Can't assign to the final variable 'a'. const int b = 1; // b = 2; // => Error: Can't assign to the const variable 'b'. final List<int> c = [1,2,3,4,5]; // c.add(6); // => OK。つまり変数のメモリ領域の中身までは関与しない。 const List<int> d = [1,2,3,4,5]; // d.add(6); // => Unsupported operation: Cannot add to an unmodifiable list // 変数のメモリ領域の中身も変更不可。 }
- final/constの違いは上記
制御構文
if
void main(List<String> args) { var a = args[0].toLowerCase(); if (a == "john") { print("John is a great Rock'n Roller!"); } else if (a == "paul") { print("Paul is a great Pop Maker!"); } else if (a == "george") { print("George is a greate slide guitarlist!"); } else if (a == "ringo") { print("Ringo's drum gives rock-solid back-beat!"); } else { print("${a}? who?"); } }
- コマンドラインでやってみた。
void main() { int a = 1; String b = "hoge"; if (a) print(true); // Error: A value of type 'String' can't be assigned to a variable of type 'bool'. if (b) print(true); // Error: A value of type 'String' can't be assigned to a variable of type 'bool'. }
- ifはほんとにboolしか取れない。
switch
void main(List<String> args) { var a = args[0].toLowerCase(); switch (a) { case 'john': print("John is a great Rock'n Roller!"); break; case 'paul': print("Paul is a great Pop Maker!"); break; case 'george': print("Ringo's drum gives rock-solid back-beat!"); break; case 'ringo': print("George is a greate slide guitarlist!"); break; default: print("${a}? who?"); } }
- breakの省略はできない(エラー)
void main(List<String> args) { var a = args[0].toLowerCase(); switch (a) { case 'john': print("John is a great Rock'n Roller!"); case 'paul': print("Paul is a great Pop Maker!"); case 'george': print("George is a greate slide guitarlist!"); case 'ringo': print("Ringo's drum gives rock-solid back-beat!"); break; default: print("${a}? who?"); } } // => Error: Switch case may fall through to the next case. // case 'john': // ^ // case 'paul': // ^ // case 'george':
- caseが空ならOK
void main(List<String> args) { var a = args[0].toLowerCase(); switch (a) { case 'john': case 'paul': case 'george': case 'ringo': print("The Beatles are great!"); break; default: print("${a}? who?"); } }
- continueとラベルを使う
void main(List<String> args) { var a = args[0].toLowerCase(); switch (a) { case 'john': print("John is a great Rock'n Roller!"); continue PAUL; PAUL: case 'paul': print("Paul is a great Pop Maker!"); continue GEORGE; GEORGE: case 'george': print("George is a greate slide guitarlist!"); continue RINGO; RINGO: case 'ringo': print("Ringo's drum gives rock-solid back-beat!"); break; default: print("${a}? who?"); } }
for
void main() { for (var i = 0; i < 10; i++) { print(i); } }
while/do while
void main() { var i = 0; while (i < 10) { print(i); i++; } }
void main() { var i = 0; do { print(i); i++; } while (i < 10); }
break/continue
void main() { var i = 1; var j = 10; while (true) { print(i); i++; if (i > j) break; } } // => 1 2 3 4 5 6 7 8 9 10
void main() { for (var i = 1; i <= 10; i++) { if (i % 2 == 1) continue; print(i); } } // => 2 4 6 8 10
for in/forEach
void main() { List<String> a = ["John", "Paul", "George", "Ringo"]; a.forEach((i) => print(i)); } // => John Paul George Ringo
void main() { List<String> a = ["John", "Paul", "George", "Ringo"]; for (var i in a) { print("${i} is great!"); } } // => John is great! Paul is great! George is great! Ringo is great!
関数
基本
bool isOdd(int number) { if (number % 2 == 1) return true; return false; } void main(List<String> args) { int a = int.parse(args[0]); print(isOdd(a)); }
-戻り値の型 関数名(引数の型 引数) { ... }
。型アノテーション推奨。
bool isOdd(int number) =>number % 2 == 1;
- 上記だと1行で書ける。
=> expr
は{return expr;}
と同じこと。
void echo() => print("odd checker"); void main() { echo(); // "odd checker" }
- 戻り値なしは
void
String repeat(String string, int number) { return "${string} " * number; } void main(List<String> args) { String a = args[0]; int b = int.parse(args[1]); print(repeat(a, b)); }
- 複数の引数はカンマ区切り
int tashizan({int num1 = 0, int num2 = 0}) { return num1 + num2; } void main(List<String> args) { int c = int.parse(args[0]); int d = int.parse(args[1]); print(tashizan(num1: c, num2: d)); }
- 関数の引数を
{}
で囲むと仮引数を仮引数名: 値
で指定できる。 - 一つ前と同じ例にしようとしたらnull safetyでうまくいかなかった・・・
String repeat(String string, {int number = 1}) { return "${string} " * number; } void main(List<String> args) { String a = args[0]; int b = int.parse(args[1]); print(repeat(a, number: b)); }
- 引数にデフォルト値を指定する場合は
{}
でくくって=
で指定 - 引数の指定も
仮引数名: 値
になるので注意 - null safetyを回避するにはデフォルト値の設定は必須になるっぽい
無名関数
void main() { List<String> a = ["John", "Paul", "George", "Ringo"]; a.forEach((i) => print(i)); }
- イテレータのコールバックで使う事が多い。
Function printName = (String i) { print("${i}"); }; void main() { List<String> a = ["John", "Paul", "George", "Ringo"]; a.forEach( (i) { printName(i); }); }
- 上と等価
Function printName = (String i) => print("${i}");
- 処理が1行なら、関数も1行で書ける
void main() { var multiply = (int num) => print(num * 2); List<int> list = [1,2,3]; list.forEach(multiply); } // => 2 4 6
- 関数の引数として関数を渡せる
スコープ
String a = "one"; void main() { String a = "two"; print(a); // "two" void print_a() { String a = "thee"; print(a); // "three" } print_a(); { String a = "four"; print(a); // "four" } }
{ ... }
のブロックで単純にスコープが分かれる。
クロージャ
Function tashizan(int x) { return (int i) => x + i; } void main() { var add1 = tashizan(1); var add2 = tashizan(2); var add3 = tashizan(3); print(add1(1)); // 2 print(add2(2)); // 4 print(add3(3)); // 6 }
- 関数の戻り値に関数を返す
Function outer() { int x = 10; return () => x++; } void main() { var func1 = outer(); print(func1()); // 10 print(func1()); // 11 print(func1()); // 12 }
- やっぱりクロージャむずい><
assert
void main() { int a = 10; assert(a < 5); print(a); }
- コマンドラインだと
--enable-asserts
をつけて実行する
$ dart --enable-asserts sample.dart Unhandled exception: 'file:///Users/xxxxx/repository/dart_sandbox/sample.dart': Failed assertion: line 3 pos 10: 'a < 5': is not true. #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39) #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5) #2 main (file:///Users/kun432/repository/dart_sandbox/fff:3:10) #3 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:311:19) #4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
- productionだと無視される
演算子
四則計算とか比較は他の言語とほとんど同じ。特徴的なやつだけ。
- 型チェック
void main() { int a = 10; if(a is int) print(true); // true if(a is! String) print(true); // true }
例外
void main(List<String> args) { String a = args[0].toLowerCase(); try { if (a == 'john' || a == 'paul' || a == 'george' || a == 'ringo') { print('They are great!'); } else if(a == 'martin' || a == 'brian') { throw FormatException('They are great too, but not a member.'); } else if (a == 'mick' || a == 'keith' || a == 'ron' || a == 'charlie') { throw Exception('They are great too, but not fab four.'); } else { throw ('${a}? who?'); } } on FormatException catch (e) { print('Error1: ${e}'); } on Exception catch (e) { print('Error2: ${e}'); } catch (e) { print('Unknown error: ${e}'); } }
try ~ catch
も普通。- tryの中で
throw
を投げて、catchで受ける on 〜Exception catch
で特定の例外を受けるon Exception catch
ですべての例外を拾うcatch
でエラーも含めて拾う
- tryの中で
catch (e)
でエラー内容を拾う、catch (e, s)
でスタックトレースも拾える
まとめ
続きはまた更新します。
参考にさせていただいた書籍・サイト

Dart入門 - Dartの要点をつかむためのクイックツアー
- 作者:ナカノヒトシ
- 発売日: 2018/09/09
- メディア: Kindle版