ZetCode

Dart UnmodifiableListView

最后修改于 2025 年 4 月 4 日

在 Dart 中,UnmodifiableListView 是 List 的一个不可修改视图。它包装了一个现有的 List,并阻止通过该视图进行修改。

UnmodifiableListView 实现 List 接口,但对于会修改列表的操作会抛出 UnsupportedError。它对于安全地暴露内部列表非常有用。

创建 UnmodifiableListView

创建 UnmodifiableListView 的最简单方法是使用其构造函数。

main.dart
import 'dart:collection';

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var unmodifiableView = UnmodifiableListView(numbers);
  
  print(unmodifiableView);
  
  try {
    unmodifiableView.add(6); // Will throw
  } catch (e) {
    print('Error: $e');
  }
}

我们创建了一个可变列表的不可修改视图。尝试修改它会抛出 UnsupportedError。原始列表仍然可以修改。

$ dart main.dart
[1, 2, 3, 4, 5]
Error: Unsupported operation: Cannot add to an unmodifiable list

UnmodifiableListView 与 List 操作

UnmodifiableListView 支持所有非修改性 List 操作,例如访问和迭代。

main.dart
import 'dart:collection';

void main() {
  var fruits = ['apple', 'banana', 'orange'];
  var unmodifiableFruits = UnmodifiableListView(fruits);
  
  // Access elements
  print('First fruit: ${unmodifiableFruits[0]}');
  print('Length: ${unmodifiableFruits.length}');
  
  // Iteration
  for (var fruit in unmodifiableFruits) {
    print(fruit.toUpperCase());
  }
  
  // Non-modifying methods
  print('Contains apple: ${unmodifiableFruits.contains('apple')}');
  print('Index of banana: ${unmodifiableFruits.indexOf('banana')}');
}

我们演示了 UnmodifiableListView 上的只读操作。所有标准的 List 访问方法都按预期工作,但不具备修改功能。

$ dart main.dart
First fruit: apple
Length: 3
APPLE
BANANA
ORANGE
Contains apple: true
Index of banana: 1

保护内部列表

UnmodifiableListView 通常用于安全地暴露内部列表。

main.dart
import 'dart:collection';

class Team {
  final List<String> _members = [];
  
  UnmodifiableListView<String> get members => 
      UnmodifiableListView(_members);
      
  void addMember(String name) {
    _members.add(name);
  }
}

void main() {
  var team = Team();
  team.addMember('Alice');
  team.addMember('Bob');
  
  print('Team members: ${team.members}');
  
  try {
    team.members.add('Charlie'); // Will throw
  } catch (e) {
    print('Cannot modify: $e');
  }
}

Team 类通过 UnmodifiableListView 公开其成员。客户端可以读取但不能直接修改列表。修改必须通过 addMember 进行。

$ dart main.dart
Team members: [Alice, Bob]
Cannot modify: Unsupported operation: Cannot add to an unmodifiable list

UnmodifiableListView 与 Unmodifiable List 的区别

UnmodifiableListView 与创建真正的不可修改列表不同。

main.dart
import 'dart:collection';

void main() {
  var original = [1, 2, 3];
  var view = UnmodifiableListView(original);
  var unmodifiableCopy = List.unmodifiable(original);
  
  original.add(4); // Modifies the original
  
  print('View: $view'); // Reflects changes
  print('Copy: $unmodifiableCopy'); // Doesn't change
  
  try {
    view.add(5); // Throws
    unmodifiableCopy.add(5); // Also throws
  } catch (e) {
    print('Both prevent modification');
  }
}

UnmodifiableListView 是一个实时视图,反映了对原始列表的更改。List.unmodifiable 创建一个独立的副本,该副本不会改变。

$ dart main.dart
View: [1, 2, 3, 4]
Copy: [1, 2, 3]
Both prevent modification

与其他集合结合使用

UnmodifiableListView 可以与其他集合操作结合使用。

main.dart
import 'dart:collection';

void main() {
  var data = [10, 20, 30, 40, 50];
  
  // Create filtered unmodifiable view
  var evenView = UnmodifiableListView(
      data.where((n) => n % 2 == 0).toList());
  
  print('Even numbers: $evenView');
  
  // Create transformed unmodifiable view
  var squaredView = UnmodifiableListView(
      data.map((n) => n * n).toList());
  
  print('Squared numbers: $squaredView');
  
  // Attempt modification
  try {
    evenView.removeLast();
  } catch (e) {
    print('Cannot modify: $e');
  }
}

我们通过结合过滤和映射与 UnmodifiableListView 来创建专门的不可修改视图。这些视图在显示转换后的数据时保持不变。

$ dart main.dart
Even numbers: [20, 40, 50]
Squared numbers: [100, 400, 900, 1600, 2500]
Cannot modify: Unsupported operation: Cannot remove from an unmodifiable list

最佳实践

来源

Dart UnmodifiableListView 文档

本教程通过实际示例介绍了 Dart 的 UnmodifiableListView,演示了其关键功能和用法模式。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程