前言
在 Dart 编程中,List 是一种非常常用的数据结构,它允许我们存储和操作有序的对象集合。List 提供了丰富的 API 来满足各种数据操作需求。本文将详细介绍 Dart 中 List 的各种用法和技巧,帮助你在编写 Dart 程序时更加高效。
具体用法
List 的基本用法
创建 List
dart
List<int> numbers = [1, 2, 3, 4, 5];
List<String> fruits = ['apple', 'banana', 'cherry'];
构造函数创建
dart
List<int> emptyList = List<int>.empty(growable: true); // 空列表
//growable: 一个布尔值,表示列表是否可以增长。默认值是 false,表示列表是固定长度的。如果设置为 true,则列表是可增长的
List<int> fixedLengthList = List<int>.filled(5, 0); // 固定长度,初始化为0
List.from :用于创建一个新的列表,并从一个可迭代对象(例如另一个列表、集合等)复制元素
iterable: 要从中复制元素的可迭代对象。
growable: 一个可选的布尔值,表示列表是否可以增长。默认值是 true,表示列表是可增长的。
创建一个新的列表从现有列表
dart
void main() {
// 创建一个源列表
List<int> originalList = [1, 2, 3, 4, 5];
// 使用 List.from 创建一个新的列表
List<int> newList = List.from(originalList);
print(newList); // 输出: [1, 2, 3, 4, 5]
// 修改新的列表,不影响原始列表
newList[0] = 10;
print(originalList); // 输出: [1, 2, 3, 4, 5]
print(newList); // 输出: [10, 2, 3, 4, 5]
}
从集合创建列表
dart
void main() {
// 创建一个源集合
Set<String> fruitSet = {'apple', 'banana', 'cherry'};
// 使用 List.from 创建一个新的列表
List<String> fruitList = List.from(fruitSet);
print(fruitList); // 输出: ['apple', 'banana', 'cherry']
}
创建一个不可增长的列表
dart
void main() {
// 使用 List.from 创建一个不可增长的列表
List<int> fixedList = List.from([1, 2, 3], growable: false);
print(fixedList); // 输出: [1, 2, 3]
// 尝试添加元素会导致错误
// fixedList.add(4); // 这将抛出异常
}
List.of: 是一个构造函数,用于从一个可迭代对象(例如另一个列表、集合等)创建一个新的列表。与 List.from 类似,List.of 也用于复制元素并生成一个新的 List 对象。它主要用于确保从现有集合创建的列表是分离的,并且可以根据需要指定列表是否可增长。
dart
void main() {
// 创建一个源列表
List<int> originalList = [1, 2, 3, 4, 5];
// 使用 List.of 创建一个新的列表
List<int> newList = List.of(originalList);
print(newList); // 输出: [1, 2, 3, 4, 5]
// 修改新的列表,不影响原始列表
newList[0] = 10;
print(originalList); // 输出: [1, 2, 3, 4, 5]
print(newList); // 输出: [10, 2, 3, 4, 5]
}
List.generate : 是一个构造函数,用于创建一个新的列表,并通过调用一个生成函数来初始化每个元素。这种方法非常适合需要根据某种规则或算法动态生成列表内容的场景
length: 列表的长度,必须是一个非负整数。
generator: 一个函数,用于生成列表的每个元素。这个函数接收一个整数(元素的索引)作为参数,并返回一个元素。
growable: 一个可选的布尔值,表示列表是否可以增长。默认值是 true,表示列表是可增长的。
创建一个简单的数字列表
dart
void main() {
// 使用 List.generate 创建一个包含 0 到 4 的列表
List<int> numbers = List.generate(5, (index) => index);
print(numbers); // 输出: [0, 1, 2, 3, 4]
}
根据规则生成元素
dart
void main() {
// 创建一个列表,其中每个元素是索引的平方
List<int> squares = List.generate(5, (index) => index * index);
print(squares); // 输出: [0, 1, 4, 9, 16]
}
创建一个不可增长的列表
dart
void main() {
// 使用 List.generate 创建一个不可增长的列表
List<String> repeatedWords = List.generate(3, (index) => 'word', growable: false);
print(repeatedWords); // 输出: ['word', 'word', 'word']
// 尝试添加元素会导致错误
// repeatedWords.add('another word'); // 这将抛出异常
}
List.unmodifiable 是一个构造函数,用于创建一个不可变(只读)的列表。使用 List.unmodifiable 可以确保列表的内容在创建后不能被修改,这对于需要保护数据不被意外更改的场景非常有用
List.unmodifiable 接受一个可迭代对象(iterable)作为参数,并返回一个新的不可变列表。
创建不可变列表
dart
void main() {
// 创建一个源列表
List<int> originalList = [1, 2, 3, 4, 5];
// 使用 List.unmodifiable 创建一个不可变的列表
List<int> unmodifiableList = List.unmodifiable(originalList);
print(unmodifiableList); // 输出: [1, 2, 3, 4, 5]
// 尝试修改列表会导致错误
// unmodifiableList[0] = 10; // 这将抛出异常
// unmodifiableList.add(6); // 这也会抛出异常
}
从其他集合创建不可变列表
dart
void main() {
// 创建一个源集合
Set<String> fruitSet = {'apple', 'banana', 'cherry'};
// 使用 List.unmodifiable 创建一个不可变的列表
List<String> unmodifiableFruitList = List.unmodifiable(fruitSet);
print(unmodifiableFruitList); // 输出: ['apple', 'banana', 'cherry']
}
常用属性
length: 获取列表的长度。
dart
int len = numbers.length;
isEmpty 和 isNotEmpty: 检查列表是否为空。
dart
bool empty = numbers.isEmpty;
bool notEmpty = numbers.isNotEmpty;
常用方法
添加和删除元素
add: 添加单个元素到列表的末尾。
dart
numbers.add(1);
addAll: 添加多个元素到列表。
dart
numbers.addAll([7, 8, 9]);
insert: 在指定索引处插入元素。
dart
numbers.insert(1, 10); // 在索引 1 处插入 10
insertAll: 在指定索引处插入多个元素。
dart
numbers.insertAll(2, [20, 30]);
setAll: ,用于将另一个列表(或任何可迭代对象)的元素复制到当前列表中的指定位置。这个方法允许你用新的数据替换部分列表,非常适合需要批量更新列表内容的场景。
dart
void main() {
List<int> targetList = [0, 0, 0, 0, 0];
List<int> sourceList = [1, 2, 3];
// 从索引1开始,将 sourceList 的所有元素复制到 targetList
targetList.setAll(1, sourceList);
print(targetList); // 输出: [0, 1, 2, 3, 0]
}
setAll 不会改变列表的长度,它只替换现有的元素。因此,目标列表必须有足够的元素来完成替换。
remove: 删除列表中的第一个匹配元素。
dart
numbers.remove(3);
removeAt: 删除指定索引处的元素。
dart
numbers.removeAt(0);
removeLast: 删除列表中的最后一个元素。
dart
numbers.removeLast();
removeWhere:用于从列表中移除所有满足指定条件的元素
dart
class Person {
String name;
int age;
Person(this.name, this.age);
}
void main() {
List<Person> people = [
Person('Alice', 30),
Person('Bob', 25),
Person('Charlie', 35),
Person('David', 28),
];
// 移除所有年龄小于30的人员
people.removeWhere((person) => person.age < 30);
print(people.map((person) => person.name).toList()); // 输出: ['Alice', 'Charlie']
}
retainWhere: 用于从列表中保留所有满足指定条件的元素,并移除其余的元素。这个方法通过一个谓词函数来确定哪些元素应该被保留,非常适合需要根据复杂条件筛选列表元素的场景。
dart
void main() {
List<int> numbers = [1, 2, 3, 4, 5, 6];
// 保留所有偶数
numbers.retainWhere((number) => number % 2 == 0);
print(numbers); // 输出: [2, 4, 6]
}
clear: 清空列表。
dart
numbers.clear();
访问和修改元素
通过索引访问元素:
dart
int firstElement = numbers[0];
通过索引修改元素:
dart
numbers[1] = 15;
查找元素
indexOf: 返回第一个匹配元素的索引
dart
int index = numbers.indexOf(4);
lastIndexOf: 返回最后一个匹配元素的索引。
dart
int lastIndex = numbers.lastIndexOf(4);
indexWhere: 是 List 类的一个方法,用于查找列表中第一个满足指定条件的元素的索引。与 indexOf 不同,indexWhere 允许你使用一个谓词(条件函数)来定义查找条件。
indexWhere 方法有两个参数:
test: 一个函数,接受列表元素作为参数,并返回一个布尔值。该函数用于定义查找条件。
start: 一个可选参数,指定从哪个索引开始查找。默认从列表的开头开始。
indexWhere 返回第一个满足条件的元素的索引,如果没有元素满足条件,则返回 -1。
dart
void main() {
List<int> numbers = [10, 20, 30, 40, 50];
// 从索引3开始查找第一个大于25的元素的索引
int index = numbers.indexWhere((number) => number > 25, 3);
print(index); // 输出: 3
}
lastIndexWhere:是 List 类的一个方法,用于查找列表中最后一个满足指定条件的元素的索引。与 indexWhere 类似,lastIndexWhere 允许你使用一个谓词(条件函数)来定义查找条件,但它是从列表的末尾向前查找的
dart
class Person {
String name;
int age;
Person(this.name, this.age);
}
void main() {
List<Person> people = [
Person('Alice', 30),
Person('Bob', 25),
Person('Charlie', 35),
Person('David', 28),
];
// 查找最后一个年龄大于30的人的索引
int index = people.lastIndexWhere((person) => person.age > 30);
print(index); // 输出: 2
}
contains: 检查列表是否包含某个元素。
dart
bool hasFive = numbers.contains(5);
排序和反转
sort: 对列表进行排序。
dart
numbers.sort(); // 升序排序
reversed: 返回一个迭代器,顺序是反转的。
dart
var reversedNumbers = numbers.reversed;
shuffle: 随机打乱列表顺序。
dart
numbers.shuffle();
遍历
forEach: 对每个元素执行一个函数。
dart
numbers.forEach((number) {
print(number);
});
map: 返回一个新的迭代器,其元素是对原列表每个元素应用转换函数的结果。
dart
//可以将原list数据进行转换
var doubled = numbers.map((number) => number * 2);
其他方法
sublist: 返回一个子列表。
dart
var sublist = numbers.sublist(1, 3); // 从索引 1 到 3 的子列表
getRange 是 List 类的一个方法,用于获取列表中指定范围的元素。它返回一个 Iterable,包含指定范围内的元素。这个方法非常有用,当你只需要列表中的一个子集时,可以避免创建整个列表的副本。
dart
void main() {
List<int> numbers = [10, 20, 30, 40, 50];
// 获取索引 1 到 3(不包含 3)的元素
Iterable<int> subrange = numbers.getRange(1, 3);
print(subrange.toList()); // 输出: [20, 30]
}
sublist和getRange
join: 将列表的所有元素连接成一个字符串。
dart
// eg:"a,b,c"
String joined = fruits.join(', ');
asMap: 返回一个映射,键是索引,值是列表中的元素。
dart
//eg: List<int> numbers = [1, 2, 3, 4, 5]; to {1:1,2:2,3:3,4:4}
Map<int, int> map = numbers.asMap();
castFrom: 是一个静态方法,用于将一个列表转换为另一个类型的列表。这种转换是类型安全的,它在运行时检查元素的类型以确保它们与目标类型匹配。如果类型不匹配,会抛出异常。
简单类型转换
dart
void main() {
// 创建一个动态类型的列表
List<dynamic> dynamicList = [1, 2, 3, 4, 5];
// 使用 List.castFrom 将其转换为一个具体类型的列表
List<int> intList = List.castFrom<dynamic, int>(dynamicList);
print(intList); // 输出: [1, 2, 3, 4, 5]
}
类型不匹配示例
如果尝试将类型不匹配的元素转换,会抛出异常:
dart
void main() {
// 创建一个包含不同类型元素的动态列表
List<dynamic> mixedList = [1, 'two', 3];
try {
// 尝试将其转换为一个整型列表
List<int> intList = List.castFrom<dynamic, int>(mixedList);
} catch (e) {
print(e); // 输出: 类型转换错误
}
}
cast List.cast 是一个实例方法,用于将列表中的元素转换为指定类型的视图。这种转换是类型安全的,但在使用时会进行运行时检查,以确保元素类型与目标类型匹配。cast 方法不会创建新的列表,而是返回一个新的视图,如果访问的元素类型不正确,则会在运行时抛出异常。
List.cast 方法不需要参数,它返回一个新的 List 视图,假设所有元素都能安全地转换为目标类型。
dart
void main() {
// 创建一个动态类型的列表
List<dynamic> dynamicList = [1, 2, 3, 4, 5];
// 使用 cast 将其转换为一个具体类型的列表视图
List<int> intList = dynamicList.cast<int>();
print(intList); // 输出: [1, 2, 3, 4, 5]
}
类型不匹配示例
dart
void main() {
// 创建一个包含不同类型元素的动态列表
List<dynamic> mixedList = [1, 'two', 3];
try {
// 使用 cast 创建一个整型列表视图
List<int> intList = mixedList.cast<int>();
// 访问时会检查类型,如果不匹配,会抛出异常
print(intList[1]); // 这将抛出异常
} catch (e) {
print(e); // 输出: 类型转换错误
}
}
copyRange: 是一个实用函数,用于将一个列表的部分内容复制到另一个列表中。它是 dart:core 库中的 List 类提供的静态方法。copyRange 函数非常适用于需要复制部分数据的场景,比如在排序算法或数据处理过程中。
copyRange 的函数构造如下:
dart
void copyRange<T>(
List<T> target,//目标列表,数据将被复制到这个列表中。
int at,//目标列表中开始复制的起始索引。
Iterable<T> source, {//源数据的可迭代对象,即要复制的数据来源。
int? start,// 可选参数,指定源数据的起始索引(包含)。默认从第一个元素开始。
int? end,// 可选参数,指定源数据的结束索引(不包含)。默认复制到最后一个元素。
})
基本用法
dart
import 'dart:core';
void main() {
List<int> targetList = [0, 0, 0, 0, 0];
List<int> sourceList = [1, 2, 3, 4, 5];
// 将 sourceList 的前两个元素复制到 targetList 的起始位置
List.copyRange(targetList, 0, sourceList, start: 0, end: 2);
print(targetList); // 输出: [1, 2, 0, 0, 0]
// 将 sourceList 的所有元素复制到 targetList 的第二个位置开始
List.copyRange(targetList, 1, sourceList);
print(targetList); // 输出: [0, 1, 2, 3, 4]
}
writeIterable: 是 dart:core 库中的一个实用函数,用于将一个可迭代对象的内容写入到一个目标列表中。这个函数提供了一种简单的方法来将迭代内容复制到列表的指定位置。
writeIterable 的函数构造如下:
dart
void writeIterable<T>(
List<T> target,//目标列表,数据将被写入到这个列表中。
int at,//目标列表中开始写入的起始索引。
Iterable<T> source//要写入的数据来源,一个可迭代对象。
)
基本用法
dart
import 'dart:core';
void main() {
List<int> targetList = [0, 0, 0, 0, 0];
Iterable<int> sourceIterable = [1, 2, 3];
// 将 sourceIterable 的元素写入到 targetList,从索引 1 开始
List.writeIterable(targetList, 1, sourceIterable);
print(targetList); // 输出: [0, 1, 2, 3, 0]
}
注意事项
writeIterable、copyRange 会直接修改目标列表 target。确保目标列表从指定索引开始有足够的空间来容纳源数据。
如果目标列表的空间不够,可能会导致运行时错误,因此在使用前要确保目标列表的大小适当。
end
Dart 中的 List 是一种强大且灵活的数据结构,提供了丰富的 API 来满足各种需求。无论是简单的增删查改,还是复杂的排序和遍历,List 都能高效地完成任务。希望通过本文的介绍,大家能够更好地掌握 Dart 中 List 的用法,为开发高效的 Dart 应用程序打下坚实的基础。
如果你有任何疑问或需要进一步的帮助,欢迎在评论区留言与我们交流!