ZetCode

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 的 ListBase,并提供了实际示例,演示了如何高效地创建自定义列表实现。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程