docs

TOP(About this memo)) > 一覧(Dart) > 型

Dartsの型システム

sound type system

組み込み型(Built-in types)

Dart のすべての変数はオブジェクト (クラスのインスタンス) を参照する

… every variable in Dart refers to an object—an instance of a class …

リテラル

(IMO)シャロコピー・ディープコピーについて

class A {
  String name;
  
  @override
  String toString() {
    return name;
  }
  
  A(this.name);
}

void main() {
  final a = [A("initial name")];
  
  final b = a;
  final c = [...a];
  final d = [...a.map((a)=>A(a.name)).toList()];
  final e = [...a.map((a)=>A("dummy name")).toList()];
  e[0].name = a[0].name;
  final f = [...a.map((a)=>A(String.fromCharCodes(a.name.codeUnits))).toList()];
  
  a[0].name = "changed name";
  
  print("a: $a, a.hashCode:${a.hashCode}, a.name.hashCode: ${a[0].name.hashCode}");
  print("b: $b, b.hashCode:${b.hashCode}, b.name.hashCode: ${b[0].name.hashCode}");
  print("c: $c, c.hashCode:${c.hashCode}, c.name.hashCode: ${c[0].name.hashCode}");
  print("d: $d, d.hashCode:${d.hashCode}, d.name.hashCode: ${d[0].name.hashCode}");
  print("e: $e, e.hashCode:${e.hashCode}, e.name.hashCode: ${e[0].name.hashCode}");
  print("f: $f, f.hashCode:${f.hashCode}, f.name.hashCode: ${f[0].name.hashCode}");
}

/*
出力例: 
a: [changed name], a.hashCode:189698827, a.name.hashCode: 321055206
b: [changed name], b.hashCode:189698827, b.name.hashCode: 321055206 // リストも中身もシャローコピー(変更前)
c: [changed name], c.hashCode:4799202, c.name.hashCode: 321055206  // リスト自体はディープコピー、中身はシャローコピー(変更前)
d: [initial name], d.hashCode:115071515, d.name.hashCode: 1892746 // リスト自体はディープコピー、中身はシャローコピー(変更後)
e: [initial name], d.hashCode:718419543, e.name.hashCode: 1892746 // リスト自体はディープコピー、中身はシャローコピー(変更後)
f: [initial name], f.hashCode:896788831, f.name.hashCode: 1892746 //  リスト自体はディープコピー、中身はシャローコピー(変更後) ※ String.hasCodeはcode unitsを参照するため、String.fromCharCodesから作成しても別hash(別オブジェクト)とはならない。

*/

Object?とdynamic

void f(Object o) {
  o.toString();
  o.aaaa();//コンパイルエラー
}

void f2(dynamic o) {
  o.toString();
  o.aaaa();//コンパイルエラーにならない
}

String

var s0 = "String";
var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
print(s1) // String concatenation works even over line breaks.
var s2 = 'The + operator ' + 'works, as well.';
var s3 = '''
You can create
multi-line strings like this one.
''';
var s4 = """This is also a
multi-line string.""";

DartではStringはUTF-16でエンコードされる

The characters of a string are encoded in UTF-16. Decoding UTF-16, which combines surrogate pairs, yields Unicode code points. Following a similar terminology to Go, Dart uses the name ‘rune’ for an integer representing a Unicode code point. Use the runes property to get the runes of a string.

const string = 'Dart';
final runes = string.runes.toList();
print(runes); // [68, 97, 114, 116]

Iterable

リスト

var list = [
  'Car',
  'Boat',
  'Plane',
];
void main() {
  final l = [3,2,5,7,0];
  l.sort((int a, int b) => a - b);// 昇順
  print(l);
  l.sort((int a, int b) => b - a);// 降順
  print(l);
  l.sort((int a, int b) => a.compareTo(b));// 昇順
  print(l);
  l.sort((int a, int b) => b.compareTo(a));// 降順
  print(l);
}

セット

Set<String> names = {};//Creates a set
var names = {}; // Creates a map, not a set.
<String>{"aaaa"}.contains("aaaa"); // set
<String, String>{"aaaa": "aaaa"}.containsKey("aaaa"); // map

マップ

var pages = <String, String>{
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};
pages['spaces.txt'] = 'space';
print(pages['index.html']);
print(pages['notFound.html']);// null。キーがない場合はnullとなる。
print(pages[4]);// 型が異なってもエラーにならない。(警告は出る)
var empty = <String, String>{};// 空のマップ

Pattern

var numList = [1, 2, 3];
var [a, b, c] = numList;
print(a + b + c);// 6
var (d, [e, f]) = ('str', [1, 2]);
for (var MapEntry(:key, value: c) in {'a': 23,'b': 100}.entries) {
  print('$key, $c');
}
//a, 23
//b, 100

キーや値の取り出し、リスト<->マップの変換、マッピング、抽出、繰り返し

print({'a' : 'aaa', 'b' : 'bbb', 'c' : 'ccc',}.keys);// (a, b, c)
print({'a' : 'aaa', 'b' : 'bbb', 'c' : 'ccc',}.keys.toList());// [a, b, c]
print({'a' : 'aaa', 'b' : 'bbb', 'c' : 'ccc',}.values.toList());// [aaa, bbb, ccc]
print([1,2,3].where((e)=> e > 2 ).toList());// [3]
print(["a", "b", "c"].asMap());// {0: a, 1: b, 2: c}
print(["a", "b", "c"].asMap().entries);// (MapEntry(0: a), MapEntry(1: b), MapEntry(2: c))
print(["a", "b", "c"].asMap().entries.map((e)=>"${e.key}${e.value}").toList());// [0a, 1b, 2c]
["test", "test2"].map((item) => item.toUpperCase()).forEach(print);

Record型

void main() {
  print(getResponse());// ({result: success, data: }, 200)
  print(getResponse2());// (body: {result: success, data: }, responseCode: 200)
  print(getResponse().$1);
  print(getResponse().$2);
  print(getResponse2().body);
  print(getResponse2().responseCode);

  // pattern variable declaration
  final (b, r) = getResponse();
  final (:body, :responseCode) = getResponse2();
  // final (:body, :_) = getResponse2();//エラーとなる。値の無視はできない。
  final (body:b2, responseCode:r2) = getResponse2();
  final (body:b3, responseCode:_) = getResponse2();// 値の無視ができる
  print("$b, $r, $body, $responseCode, $b2, $r2");// {result: success, data: }, 200, {result: success, data: }, 200, {result: success, data: }, 200
}

(Map<String, dynamic> body, int responseCode) getResponse() => ({"result":"success", "data":""}, 200);
({Map<String, dynamic> body, int responseCode}) getResponse2() => (body:{"result":"success", "data":""}, responseCode:200);

typedef