Dart 中的聚合类型与容器类型详解
在 Dart 中,聚合类型(Aggregate Types) 和 容器类型(Container Types) 是指能够存储和管理一组数据的类型。它们的核心功能是将多个元素组合成一个整体,便于统一操作和管理。尽管这两个术语有时会被混用,但可以这样理解:
- 聚合类型:强调数据结构的"聚合"特性,即由多个元素组合而成的类型(如数组、列表、集合等)。
- 容器类型:更广泛的概念,指能够"容纳"其他对象或数据的结构(如列表、集合、映射、队列等)。
Dart 提供了多种容器类型,最核心的包括 List、Set、Map ,以及一些衍生类型(如 Queue
)。以下是详细说明:
1. 核心容器类型详解
1.1 List(列表)
List 是一种有序、可重复、可变 的集合,通过索引访问元素,类似于数组。
特性
- 有序性 :元素按插入顺序存储,可通过索引(从
0
开始)访问。 - 可重复性:允许存储重复元素。
- 可变性 :默认支持增删改操作,但可通过
const
声明不可变列表。
声明与初始化
dart
// 可变列表
List<int> numbers = [1, 2, 3]; // 显式类型
var strings = <String>['a', 'b', 'c']; // 类型推导
// 不可变列表(使用 const)
const immutableList = const [4, 5, 6]; // 无法修改
常用操作
方法/属性 | 说明 | 示例 |
---|---|---|
add(element) |
在列表末尾添加元素。 | numbers.add(4); → [1, 2, 3, 4] |
insert(index, element) |
在指定位置插入元素。 | numbers.insert(0, 0); → [0, 1, 2, 3, 4] |
remove(element) |
移除第一个匹配的元素。 | numbers.remove(2); → [1, 3, 4] |
removeAt(index) |
移除指定索引的元素。 | numbers.removeAt(0); → [2, 3, 4] |
length |
获取列表长度。 | print(numbers.length); → 4 |
[] |
通过索引访问或修改元素。 | numbers[0] = 10; → [10, 1, 2, 3] |
addAll(iterable) |
将另一个集合的元素追加到列表末尾。 | numbers.addAll([5, 6]); → [1, 2, 3, 5, 6] |
1.2 Set(集合)
Set 是一种无序、不可重复、可变的集合,用于存储唯一元素。
特性
- 无序性:元素存储顺序不固定,遍历时可能与插入顺序不同。
- 唯一性:不允许重复元素。
- 可变性 :默认支持增删操作,但可通过
const
声明不可变集合。
声明与初始化
dart
// 可变集合
Set<String> fruits = {'apple', 'banana', 'orange'}; // 显式类型
var uniqueNumbers = <int>{1, 2, 3}; // 类型推导
// 不可变集合(使用 const)
const immutableSet = const {'apple', 'banana'}; // 无法修改
常用操作
方法/属性 | 说明 | 示例 |
---|---|---|
add(element) |
添加元素,若已存在则返回 false 。 |
fruits.add('grape'); → {'apple', 'banana', 'orange', 'grape'} |
remove(element) |
移除指定元素。 | fruits.remove('banana'); → {'apple', 'orange', 'grape'} |
contains(element) |
检查元素是否存在。 | fruits.contains('apple'); → true |
addAll(iterable) |
合并另一个集合的元素(重复元素会被忽略)。 | fruits.addAll({'apple', 'mango'}); → {'apple', 'mango', ...} |
1.3 Map(映射)
Map 是一种键值对(Key-Value) 的无序集合,通过键快速查找值。键必须唯一,但值可以重复。
特性
- 无序性:元素存储顺序不固定。
- 唯一性:键必须唯一,但值可以重复。
- 快速查找:通过键查找值的时间复杂度为 O(1)。
声明与初始化
dart
// 可变映射
Map<String, int> ageMap = {'Alice': 30, 'Bob': 25}; // 显式类型
var scores = <String, double>{'Math': 90.5, 'Science': 85.0}; // 类型推导
// 不可变映射(使用 const)
const immutableMap = const {'name': 'Alice', 'age': 30}; // 无法修改
常用操作
方法/属性 | 说明 | 示例 |
---|---|---|
putIfAbsent(key, ifAbsent) |
如果键不存在,则添加键值对;否则返回现有值。 | ageMap.putIfAbsent('Charlie', () => 20); → 新增键 'Charlie' |
remove(key) |
移除指定键的条目。 | ageMap.remove('Bob'); → 移除键 'Bob' |
containsKey(key) |
检查是否存在指定键。 | ageMap.containsKey('Alice'); → true |
addAll(map) |
合并另一个 Map 的键值对(重复键会被覆盖)。 | ageMap.addAll({'Alice': 35}); → 键 'Alice' 的值被更新为 35 |
2. 其他容器类型
2.1 Queue(队列)
Queue
是一种先进先出(FIFO)的容器,需导入 dart:collection
:
dart
import 'dart:collection';
void main() {
Queue<int> queue = Queue();
queue.add(1);
queue.add(2);
print(queue.removeFirst()); // 输出 1
print(queue.first); // 输出 2
}
3. 容器类型的共同特性
所有容器类型(List、Set、Map)都实现了 Iterable
接口,支持以下操作:
-
遍历 :
dartnumbers.forEach((num) => print(num)); for (var fruit in fruits) { ... }
-
转换与筛选 :
dartvar doubled = numbers.map((x) => x * 2); // [2, 4, 6, 8] var even = numbers.where((x) => x.isEven); // 过滤偶数 var sum = numbers.reduce((a, b) => a + b); // 求和
4. 对比表格:快速选择容器类型
类型 | 有序性 | 可重复性 | 存储形式 | 适用场景 |
---|---|---|---|---|
List | ✅ | ✅ | 索引访问 | 需要有序、可重复的元素集合 |
Set | ❌ | ❌ | 唯一元素集合 | 需要去重的场景 |
Map | ❌ | ✅(值可重复) | 键值对(键唯一) | 需要通过键快速查找值的场景 |
Queue | ✅ | ✅ | 先进先出(FIFO) | 需要队列操作的场景(如任务队列) |
5. 注意事项
-
不可变容器:
- 通过
const
声明的容器(如const List
、const Set
)无法修改。 - 示例:
const colors = const ['red', 'green', 'blue'];
- 通过
-
类型安全:
- 始终使用类型注解(如
List<int>
)确保数据一致性。
- 始终使用类型注解(如
-
性能考量:
List
的索引访问是 O(1),但频繁插入/删除中间元素可能效率较低。Map
的键查找是 O(1),适合需要快速查找的场景。
6. 示例代码
dart
void main() {
// List 示例
List<int> numbers = [1, 2, 3];
numbers.add(4);
print(numbers[0]); // 输出 1
// Set 示例
Set<String> fruits = {'apple', 'banana'};
fruits.add('grape');
print(fruits.contains('apple')); // true
// Map 示例
Map<String, int> ageMap = {'Alice': 30};
ageMap['Bob'] = 25;
print(ageMap['Alice']); // 30
}
总结
- 聚合类型 和 容器类型 在 Dart 中通常指能存储一组数据的结构,核心类型为
List
、Set
、Map
。 - 根据需求选择:
- 有序、可重复 →
List
。 - 去重、无序 →
Set
。 - 键值对快速查找 →
Map
。
- 有序、可重复 →
- 充分利用容器的共同特性(如迭代、转换)和不可变性,提升代码健壮性。