📃

Dart ドキュメント読み直した備忘録

2022/11/27に公開約4,500字

Dart2.18.5で検証

Objectとdynamic

Objectは全てのオブジェクトを許容する。dynamicは全てのオブジェクトと全ての操作を許容する。

Object obj = "foo";
obj.foo(); // ビルドできない

dynamic obj = "foo";
obj.foo(); // ビルドできるが実行時にエラー

late

nullableでないインスタンス変数やトップレベル変数を後から初期化するときに使う。lateで宣言した変数は初めて使用されるときに初期化される。

これはビルドできない

String foo;

class Bar {
  String baz;
}

void main() {
  ・・・
}

lateをつける

late String foo;

class Bar {
  late String baz;
}

void main() {
  ・・・
}

また、トップレベル変数とクラス変数も初めて使用されるときに初期化される

var count = 0;

var global = (() => ++count)();

class Person {
  static int param = (() => ++count)();
}

void main() {
  var local = (() => ++count)(); // 1
  global; // 2
  Person.param; // 3
}

スプレット演算子

nullableな変数にも使える

List<int>? list;

・・・

[...?list];

List、Map、Set

List

var foo = <int>[1, 2, 3]
foo; // [1, 2, 3]

MapとSet

var foo = Map<String, int>();
foo["id"] = 1;
foo; // {id: 1}

var foo = Set();
foo.addAll([1, 2, 3]);
foo; // {1, 2, 3}

これと

var foo = <String, int>{"id": 1};
foo; // {id: 1}

var foo = <int>{1,2,3};
foo; // {1, 2, 3}

は同義である。また、それぞれifやforが使える

var list = [
  for (var i = 0; i < 3; i++) i,
  if (condition) "foo",
];
list; // [0, 1, 2, foo]

var set = {
  for (var i = 0; i < 3; i++) i,
  if (condition) "foo",
};
set; // {0, 1, 2, foo}

var map = {
  for (var i = 0; i < 3; i++) "$i": i,
  if (condition) "foo": "bar",
};
map; // {0: 0, 1: 1, 2: 2, foo: bar}

Function

Functionもオブジェクト

final String Function(int n) f = (int n) {
  return "n is $n";
};

f(1); // n is 1

戻り値を指定しないかつreturnがないとnullが返る

foo () {}
foo(); // null

オブジェクトのカスケード記法

var foo = Foo();
hoge.bar = "bar";
hoge.baz();

Foo()
  ..bar = "bar"
  ..baz();

は同義である

rethrow

これだとfooで例外が発生したところまでしか追えない

foo() {
  try {
    baz();
  } catch (e) {
    throw e;
  }
}

try {
  foo();
} catch (e, st) {
  print(st);
}

bazで例外が発生したところまで追える

foo() {
  try {
    baz();
  } catch (e) {
    rethrow;
  }
}
・・・

const

同じ内容のオブジェクトをconstで定義すると1つのインスタンスになる

class Foo {
  final String name;
  const Foo({required this.name});
}

const foo = Foo(name: "foo");

identical(foo, Foo(name: "foo")); // false
identical(foo, const Foo(name: "foo")); // true
identical(foo, const Foo(name: "fooooo")); // false

コンストラクタ

コンストラクタは継承されない

class Foo {
  String name;

  Foo(this.name);
  Foo.fromName(String v) : name = v;
  factory Foo.withName(String value) => Foo(value);
}

class Bar extends Foo {}

// 継承されないのでビルドエラー
Bar("bar"); 
Bar.fromName("bar");
Bar.withName("bar");

ただし、名前なし・引数なしコンストラクタは継承される

class Foo {
  String name;
  Foo() : name = "foo";
}

class Bar extends Foo {}

Bar();

演算子の継承、追加

operatorを使う

class Foo {
  String name;
  Foo(this.name);

  
  bool operator ==(Object other) => other is Foo && name == other.name;

  bool operator <(Object other) => true;

  
  int get hashCode => name.hashCode;
}

Foo("foo") == Foo("foo") // true
Foo("foo") <  Foo("foo") // true

noSuchMethod

オーバーライドできる

class Foo {
  
  void noSuchMethod(Invocation invocation) {
    print("${invocation.memberName}?そんなめそっどないよー");
  }
}

dynamic foo = Foo();
foo.foo();

extension

extensionで拡張できる

extension Foo on int {
  void greet () => print("I am $this");
}

10.greet(); // I am 10

enumも拡張できる

enum Status { foo, bar }

extension StatusExt on Status {
  String get name {
    switch (this) {
      case Status.foo:
        return "foo";
      case Status.bar:
        return "bar";
    }
  }
}

Status.foo.name // foo

ジェネリクスに制約をつける

extendsを使う

foo<T extends num>(T n) {}

foo(100);
foo("test"); // num型じゃないのでビルドエラー

null許容変数から非許容変数への昇格

void main() {
  List? bar;

  ・・・

  if (bar != null){
      bar.length; // !マークいらない
  }
}

ただし、ローカル変数とパラメータに対してのみ有効なため、フィールドやトップレベル変数では昇格しない

class Foo {
  List? bar;

  baz() {
    if (bar != null) {
      bar!.length; // !マークがいる
    }
  }
}

ローカル変数にいれなおすとこの機能が有効になる

class Foo {
  List? bar;

  baz() {
    var bar = this.bar;
    if (bar != null) {
      print(bar.length); // !マークいらない
    }
  }
}

Never型

関数やメソッドが正常に終了しないことを明示的に指定するための型

これだと正常に終了してしまうのでコンパイルエラー

Never foo() {}

必ず例外を投げる関数などを定義するときに使用する

Never foo() {
  throw Exception();
}

その他

参考にしたドキュメントの範囲
https://dart.dev/guides/language/language-tour
https://dart.dev/guides/language/effective-dart

Discussion

ログインするとコメントできます