Dart ListBase
最后修改日期:2025 年 6 月 4 日
在 Dart 中,ListBase 是一个抽象基类,可以简化自定义列表实现的创建。它为大多数 List 操作提供了默认实现。
ListBase 要求子类仅实现 length、operator[] 和 length= 方法。所有其他 List 操作都基于这些基本操作构建。
基本的 ListBase 实现
这是一个包装现有列表的 ListBase 的最小实现。
main.dart
import 'dart:collection';
class CustomList<E> extends ListBase<E> {
final List<E> _list = [];
@override
int get length => _list.length;
@override
set length(int newLength) {
_list.length = newLength;
}
@override
E operator [](int index) => _list[index];
@override
void operator []=(int index, E value) {
_list[index] = value;
}
// Fix: Implement addAll
@override
void addAll(Iterable<E> elements) {
_list.addAll(elements);
}
// Fix: Implement add method to allow single item insertion
@override
void add(E element) {
_list.add(element);
}
}
void main() {
var myList = CustomList<String>();
myList.addAll(['apple', 'banana', 'cherry']);
print(myList); // [apple, banana, cherry]
print(myList.reversed.toList()); // [cherry, banana, apple]
}
这个面向对象的 CustomList 类继承自 ListBase,并将所有操作委托给内部的 _list。
$ dart main.dart [apple, banana, cherry] (cherry, banana, apple)
带有验证的自定义列表
我们可以创建一个强制约束其元素的列表。
main.dart
import 'dart:collection';
class PositiveNumberList extends ListBase<int> {
final List<int> _numbers = [];
@override
int get length => _numbers.length;
@override
set length(int newLength) {
_numbers.length = newLength;
}
@override
int operator [](int index) => _numbers[index];
@override
void operator []=(int index, int value) {
if (value <= 0) throw ArgumentError('Only positive numbers allowed');
_numbers[index] = value;
}
@override
void add(int value) {
if (value <= 0) throw ArgumentError('Only positive numbers allowed');
_numbers.add(value); // Correctly adds to the internal list
}
@override
void addAll(Iterable<int> values) {
for (var value in values) {
add(value); // Ensures validation before adding
}
}
}
void main() {
try {
var numbers = PositiveNumberList();
numbers.addAll([1, 2, 3]); // Works fine
numbers.add(-5); // This will throw an error
} catch (e) {
print('Error: $e');
}
}
PositiveNumberList 会拒绝非正数。我们重写了 add 方法,以进行超出索引设置器的额外验证。
$ dart main.dart Error: ArgumentError: Only positive numbers allowed
固定大小的列表实现
这是使用 ListBase 创建固定大小列表的方法。
main.dart
import 'dart:collection';
class FixedList<E> extends ListBase<E> {
final List<E?> _list; // Allow nullable elements
FixedList(int length) : _list = List.filled(length, null);
@override
int get length => _list.length;
@override
set length(int newLength) {
throw UnsupportedError('Cannot change length of fixed list');
}
@override
E operator [](int index) {
if (_list[index] == null) {
throw StateError('Uninitialized index access');
}
return _list[index] as E;
}
@override
void operator []=(int index, E value) {
_list[index] = value;
}
@override
void add(E value) {
throw UnsupportedError('Cannot add to a fixed list');
}
@override
void addAll(Iterable<E> values) {
throw UnsupportedError('Cannot addAll to a fixed list');
}
@override
String toString() => _list.toString();
}
void main() {
var fixed = FixedList<String>(3);
fixed[0] = 'A';
fixed[1] = 'B';
fixed[2] = 'C';
print(fixed); // Outputs: [A, B, C]
try {
fixed.add('D'); // Will throw an error
} catch (e) {
print('Error: $e');
}
}
FixedList 在尝试修改其长度时会抛出异常。所有从 ListBase 继承的修改方法都会失败,因为它们最终会尝试更改长度。
$ dart main.dart [A, B, C] Error: Unsupported operation: Cannot change length of fixed list
延迟加载的列表
我们可以实现一个按需加载元素的列表。
main.dart
import 'dart:collection';
class LazyList<E> extends ListBase<E> {
final int _length;
final E Function(int) _generator;
final List<E?> _loaded;
LazyList(this._length, this._generator) : _loaded = List.filled(_length, null);
@override
int get length => _length;
@override
set length(int newLength) {
throw UnsupportedError('Cannot change length of lazy list');
}
@override
E operator [](int index) {
if (index < 0 || index >= length) {
throw RangeError.index(index, this);
}
return _loaded[index] ??= _generator(index);
}
@override
void operator []=(int index, E value) {
_loaded[index] = value;
}
}
void main() {
var lazy = LazyList<int>(5, (index) => index * 10);
print('Length: ${lazy.length}');
print('Element at 2: ${lazy[2]}');
print('Element at 4: ${lazy[4]}');
print('All elements: $lazy');
}
LazyList 仅在元素首次被访问时生成它们。_generator 函数根据索引创建元素。
$ dart main.dart Length: 5 Element at 2: 20 Element at 4: 40 All elements: [0, 10, 20, 30, 40]
复合列表
此示例将多个列表组合成一个视图。
main.dart
import 'dart:collection';
class CompositeList<E> extends ListBase<E> {
final List<List<E>> _sources;
CompositeList(this._sources);
@override
int get length => _sources.fold(0, (sum, list) => sum + list.length);
@override
set length(int newLength) {
throw UnsupportedError('Cannot change length of composite list');
}
@override
E operator [](int index) {
var remaining = index;
for (var list in _sources) {
if (remaining < list.length) {
return list[remaining];
}
remaining -= list.length;
}
throw RangeError.index(index, this);
}
@override
void operator []=(int index, E value) {
var remaining = index;
for (var list in _sources) {
if (remaining < list.length) {
list[remaining] = value;
return;
}
remaining -= list.length;
}
throw RangeError.index(index, this);
}
}
void main() {
var list1 = [1, 2, 3];
var list2 = [4, 5];
var list3 = [6, 7, 8, 9];
var composite = CompositeList([list1, list2, list3]);
print('Length: ${composite.length}');
print('Element at 0: ${composite[0]}');
print('Element at 3: ${composite[3]}');
print('Element at 5: ${composite[5]}');
print('All elements: $composite');
}
CompositeList 将多个列表呈现为一个列表,而无需复制元素。对复合列表的更改会影响原始列表。
$ dart main.dart Length: 9 Element at 0: 1 Element at 3: 4 Element at 5: 7 All elements: [1, 2, 3, 4, 5, 6, 7, 8, 9]
来源
本教程涵盖了 Dart 的 ListBase,并提供了实际示例,演示了如何高效地创建自定义列表实现。
作者
列出 所有 Dart 教程。