ZetCode

Dart MapView

最后修改于 2025 年 4 月 4 日

在 Dart 中,MapView 是 Map 的一个不可修改的视图。它提供对底层 map 数据的只读访问,同时阻止修改。

MapView 实现 Map 接口,但对于会修改 map 的操作会抛出 UnsupportedError。它对于安全地暴露 map 数据很有用。

创建 MapView

创建 MapView 最简单的方法是使用 MapView.of 构造函数。

main.dart
import 'dart:collection';

void main() {
  var originalMap = {'a': 1, 'b': 2, 'c': 3};
  var view = MapView.of(originalMap);

  print(view);
  print(view['b']); // Access works
  
  try {
    view['d'] = 4; // Will throw
  } catch (e) {
    print(e); // UnsupportedError
  }
}

我们从一个现有的 map 创建一个 MapView。虽然我们可以读取值,但任何尝试修改视图的操作都会抛出 UnsupportedError。

$ dart main.dart
{a: 1, b: 2, c: 3}
2
UnsupportedError: Cannot modify unmodifiable map

带不同 Map 类型的 MapView

MapView 可以与任何 Map 实现一起工作,包括 HashMap 和 LinkedHashMap。

main.dart
import 'dart:collection';

void main() {
  var hashMap = HashMap<String, int>();
  hashMap.addAll({'x': 10, 'y': 20, 'z': 30});
  
  var linkedMap = LinkedHashMap<String, int>();
  linkedMap.addAll({'first': 1, 'second': 2});
  
  var hashView = MapView.of(hashMap);
  var linkedView = MapView.of(linkedMap);
  
  print('HashMap view: $hashView');
  print('LinkedHashMap view: $linkedView');
}

这表明 MapView 在不同的 Map 实现中一致工作。该视图保留了原始 map 的特性。

$ dart main.dart
HashMap view: {x: 10, z: 30, y: 20}
LinkedHashMap view: {first: 1, second: 2}

MapView 操作

MapView 支持 Map 接口的所有读取操作。

main.dart
import 'dart:collection';

void main() {
  var scores = {'Alice': 90, 'Bob': 85, 'Charlie': 95};
  var scoreView = MapView.of(scores);
  
  print('Keys: ${scoreView.keys}');
  print('Values: ${scoreView.values}');
  print('Length: ${scoreView.length}');
  print('Contains Alice: ${scoreView.containsKey('Alice')}');
  print('Alice\'s score: ${scoreView['Alice']}');
  
  scoreView.forEach((k, v) => print('$k: $v'));
}

所有不修改的 Map 操作在 MapView 上都能正常工作。该视图反映了对原始 map 所做的更改。

$ dart main.dart
Keys: (Alice, Bob, Charlie)
Values: (90, 85, 95)
Length: 3
Contains Alice: true
Alice's score: 90
Alice: 90
Bob: 85
Charlie: 95

原始 Map 的实时视图

MapView 提供了一个实时视图,可以反映对原始 map 的更改。

main.dart
import 'dart:collection';

void main() {
  var original = {'a': 1, 'b': 2};
  var view = MapView.of(original);
  
  print('Initial view: $view');
  
  original['c'] = 3;
  print('After original modification: $view');
  
  original.remove('a');
  print('After original removal: $view');
}

对原始 map 的更改会立即在 MapView 中可见。这使得 MapView 非常适合需要安全共享数据的场景。

$ dart main.dart
Initial view: {a: 1, b: 2}
After original modification: {a: 1, b: 2, c: 3}
After original removal: {b: 2, c: 3}

将 MapView 与其他集合结合使用

MapView 可以与其他不可修改的集合结合使用,以实现完全安全。

main.dart
import 'dart:collection';

void main() {
  var data = {
    'users': ['Alice', 'Bob'],
    'scores': [90, 85],
    'active': true
  };
  
  var unmodifiableMap = UnmodifiableMapView(data);
  var unmodifiableLists = unmodifiableMap.map(
    (key, value) => MapEntry(
      key, 
      value is List ? List.unmodifiable(value) : value
    )
  );
  
  print(unmodifiableLists);
  
  try {
    unmodifiableLists['users'].add('Charlie'); // Fails
  } catch (e) {
    print(e); // UnsupportedError
  }
}

我们通过将 MapView 与不可修改的列表结合来创建一个完全不可修改的结构。这可以在所有级别上阻止修改。

$ dart main.dart
{users: [Alice, Bob], scores: [90, 85], active: true}
UnsupportedError: Cannot add to an unmodifiable list

最佳实践

来源

Dart MapView 文档

本教程通过实际示例介绍了 Dart 的 MapView,演示了其创建不可修改 map 视图的关键功能和用法模式。

作者

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

列出 所有 Dart 教程