Dart 集合

Dart 集合

一、Dart 內建三大集合

Dart 原生內建三種集合:ListSetMap

集合內部元素型別約束可透過泛型(Generics)設定。

集合型別核心特性字面量標記
List有序、允許重複、支援下標索引[]
Set無序、元素唯一、無下標{}(需明確標註泛型才是 Set)
Map鍵值對儲存、Key 唯一、Value 可重複{key: value}

二、List 串列(有序陣列)

1. 基礎定義與型別推斷

  • Dart 中的陣列本質是 List 物件,透過字面量 [] 建立;
  • 自動推斷型別,例如:var list = [1,2,3]List<int>,插入非 int 會報錯;
  • 支援尾隨逗號,不影響語法,減少複製貼上錯誤: var list = ['Car', 'Boat', 'Plane',];

2. 基礎操作

  1. 索引規則:從 0 開始,list.length - 1 為最後一位下標;
  2. 讀取 / 修改元素:list[index]list[index] = 新值
  3. 取得長度:.length 屬性;

範例

void main() {
	var list = [1,2,3];
	print(list.length);//輸出元素個數 3
	print(list[1]);// 輸出 2
	list[1] = 9; //修改第二個元素為9
	print(list[1]);//輸出修改後的值 9
}Code language: Dart (dart)

3. 常數串列(編譯期不可變)

字面量前加 const,執行時無法增刪改元素:

void main() {
	var constantList = const [1,2,3];
	constantList[1] = 100; // 編譯報錯
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
Unsupported operation: Cannot modify an unmodifiable list
#0      UnmodifiableListMixin.[]= (dart:_internal/list.dart:89:5)
#1      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:4:14)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#3      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

三、Set 集合

無序唯一元素

一、Set 核心特性

  • 無序:元素沒有固定下標,不能透過 [索引] 取值、修改
  • 元素唯一:自動去重,新增重複元素不會報錯,但集合只會保留一份
  • 字面量標記:大括號 {}
  • 泛型約束:可限定儲存單一型別,插入異型別編譯 / 執行報錯

空 Set 與空 Map 區分(很容易踩坑)

{} 預設識別為 Map,建立空 Set 必須明確標註泛型

void main() {
	// 空 Set<String>
	var names = <String>{};
	Set<String> names2 = {}; // 等價寫法

	// 無泛型標註,Dart 判定為 Map<dynamic, dynamic>
	var names3 = {};
}Code language: Dart (dart)
型別推斷
void main() {
	// 自動推斷 Set<String>
	var halogens = {'dog', 'cat', 'horse'};

	// 自動推斷 Set<int>
	var nums = {1, 2, 6, 2}; // 重複 2 自動去重,最終 {1,2,6}

	// 混合型別,推斷 Set<Object>(不建議,失去型別檢查)
	var mix = {1, "apple"};
}Code language: JavaScript (javascript)

自動推斷後,如果插入不同型別,會報錯

void main() {
  // 字面量全為字串,自動推斷 Set<String>
  var animals = {'dog'};
  print(animals.runtimeType); // _CompactLinkedHashSet<String>

  // 正常新增同型別字串,無報錯
  animals.add('cat');
  animals.add('pig');
  print(animals); // {dog, cat, pig}
  
  // 報錯:不能將 int 型別參數傳遞給 add 方法,方法要求 String
  animals.add(1); 
}Code language: Dart (dart)

2. 增刪與長度

  • 新增單個:.add()
  • 批量新增:.addAll()
  • 取得元素總數:.length
var elements = <String>{};
elements.add('fluorine');
elements.addAll({'chlorine', 'bromine'});
print(elements.length); //3Code language: PHP (php)

3. 常數 Set

字面量前加 const,不可新增 / 刪除元素:

final constantSet = const {'fluorine', 'chlorine'};
// constantSet.add('helium'); // 報錯Code language: PHP (php)

四、Map 映射(鍵值對)

1. 基礎特性
  • 儲存 Key-Value 成對資料;
  • Key 全域唯一,Value 可重複;
  • Key、Value 支援任意物件型別;
  • 字面量格式 {key: value}
  • 型別自動推斷:
void main() {
	var gifts = {'first': 'partridge'}; // 自動推斷出是 Map<String, String> 
	
	var nobleGases = {2: 'helium'}; // 自動推斷出是 Map<int, String>
}Code language: Dart (dart)
2. 兩種建立方式
  • 字面量建立
var gifts = {'first': 'partridge'};  Code language: Dart (dart)
  • Map 建構子建立(new 關鍵字可省略)
// 建構子寫法
var gifts = Map<String, String>();
gifts['first'] = 'partridge';Code language: JavaScript (javascript)
3. 增、查、長度
  1. 新增 / 覆蓋鍵值:map[key] = value
  2. 依據 Key 取值:map[key];Key 不存在回傳 null
  3. 取得鍵值對總數:.length
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 新增
print(gifts['first']); //取得
print(gifts['fifth']);//取得
print(gifts.length); //取得長度 Code language: PHP (php)
4. 常數 Map

字面量前加 const,鍵值對不可修改:

final constantMap = const {2: 'helium', 10: 'neon'};
// constantMap[2] = 'Helium'; // 報錯Code language: Dart (dart)

五、集合字面量增強元素

集合字面量內支援多種特殊語法,分為基礎葉片元素流程控制元素兩大類,用於簡化集合建構。

  1. 葉片基礎元素:單一運算式、Map 鍵值、空安全元素
  2. 流程控制元素:展開運算子、if 條件、for 迴圈、巢狀組合

1. 普通運算式元素

最基礎寫法,直接寫運算式,結果插入集合,下面範例第二個元素透過 2 * 3 計算,輸出 [1, 6, text]

void main() {
	var list = [1, 2 * 3, 'text'];
	print(list); //[1, 6, text]
}Code language: PHP (php)

2. 鍵值元素

僅用於 Map 字面量,格式 key運算式 : value運算式,下方範例第一組 key 與 value 皆透過運算式計算。

void main() {
	var map = {1+1: 3*8, 'name': 'apple'};
	print(map); //{2: 24, name: apple}
}Code language: Dart (dart)

3. 空安全元素(Dart ≥3.8)

語法 ?運算式:運算式不為 null 才插入集合,null 直接忽略

List 使用範例,a 為 null 不會插入,無報錯

int? a = null;
int? b = 3;
var items = [1, ?a, ?b, 5]; // [1, 3, 5]Code language: JavaScript (javascript)

Map 使用(key / value 皆可加 ?)

String? k = null;
int? v = null;
var m = {?k: ?v}; // key/value 任一為 null,整組鍵值捨棄
Code language: JavaScript (javascript)

4. Spread element 展開運算子

① 一般展開 ...

將可迭代集合所有元素平鋪插入,不可展開 null 集合

var a = [1,2,3];
var items = [0, ...a, 4]; // [0,1,2,3,4]Code language: JavaScript (javascript)
② 空安全展開 ...?

相容 null 集合:集合為 null 直接忽略,不報錯;

集合非 null 但內含 null 元素,仍會保留 null

List<int>? a = null;
var b = [1, null, 3];
var items = [0, ...?a, ...?b, 4]; // [0, 1, null, 3, 4]Code language: PHP (php)

規範:可空集合必須使用 ...?,否則編譯報錯。

5. If element 條件元素

集合內直接撰寫 if 分支,符合條件才插入對應內容,支援布林判斷、模式比對 if-case、else

基礎布林判斷
void main() {
	bool flag = true;
    var list = [0, if(flag) 1 else 99, 2];
	print(list); //[0, 1, 2]
}Code language: Dart (dart)
if-case 模式比對(型別解構、陣列解構)
void main() {
	Object data = 123;
	var info = [
	  if(data case int i) '數字:$i',
	  if(data case String s) '文字:$s'
	];
	print(info); //[數字:123]
}Code language: Dart (dart)

因為 data 是 int,因此只插入「數字:123」,不會插入文字分支

6. For element 迴圈元素

集合內直接寫 for 迴圈,迴圈自動生成多筆元素,支援 for-in / 三段式傳統 for

var nums = [2,3,4];

// for-in
var list1 = [1, for(var n in nums) n*n, 7]; // [1,4,9,16,7]

// 三段式for
var list2 = [1, for(var x=5; x>2; x--) x, 7]; // [1,5,4,3,7]Code language: JavaScript (javascript)

7. 巢狀控制流

if、for、展開符可任意多層巢狀,等同其他語言的列表推導式

範例:只保留偶數

var numbers = [1,2,3,4,5,6];
var items = [
  0,
  for(var n in numbers)
    if(n.isEven) n,
  8
]; // [0,2,4,6,8]Code language: JavaScript (javascript)

範例:巢狀 for + if + 展開

void main() {
	var ys = [1,2,3];
	var nest = [
	  ...[
		for(var x=0;x<2;x++)
		  for(var y in ys)
			if(x<y) x+y*10
	  ]
	];
	print(nest); //[10, 20, 30, 21, 31]
}Code language: Dart (dart)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *