Dart UnmodifiableMapBase
最后修改于 2025 年 4 月 4 日
在 Dart 中,UnmodifiableMapBase 是一个抽象基类,用于创建不可变 Map 视图。它提供对 Map 数据的只读访问,同时阻止修改。
UnmodifiableMapBase
实现 Map
接口,但会对所有修改操作抛出 UnsupportedError
。它对于安全地公开 Map 数据而不允许更改非常有用。
UnmodifiableMapBase 基本用法
下面是如何通过继承 UnmodifiableMapBase
来创建一个简单的不可变 Map。
main.dart
import 'dart:collection'; class UnmodifiableMapView<K, V> extends UnmodifiableMapBase<K, V> { final Map<K, V> _source; UnmodifiableMapView(this._source); @override V? operator [](Object? key) => _source[key]; @override Iterable<K> get keys => _source.keys; } void main() { final source = {'a': 1, 'b': 2, 'c': 3}; final unmodifiable = UnmodifiableMapView(source); print(unmodifiable['a']); // 1 print(unmodifiable.length); // 3 try { unmodifiable['d'] = 4; // Throws } catch (e) { print('Error: $e'); } }
我们创建一个 UnmodifiableMapView 类来包装一个源 Map。必须实现 [] 操作符和 keys getter。尝试修改将抛出异常。
$ dart main.dart 1 3 Error: Unsupported operation: Cannot modify unmodifiable map
使用工厂创建不可变 Map
一种更实用的方法是使用工厂方法来创建不可变 Map。
main.dart
import 'dart:collection'; class UnmodifiableMapFactory { static Map<K, V> create<K, V>(Map<K, V> source) { return _UnmodifiableMapWrapper(source); } } class _UnmodifiableMapWrapper<K, V> extends UnmodifiableMapBase<K, V> { final Map<K, V> _source; _UnmodifiableMapWrapper(this._source); @override V? operator [](Object? key) => _source[key]; @override Iterable<K> get keys => _source.keys; } void main() { final source = {'x': 10, 'y': 20, 'z': 30}; final unmodifiable = UnmodifiableMapFactory.create(source); print(unmodifiable['y']); // 20 print(unmodifiable.containsKey('x')); // true try { unmodifiable.clear(); // Throws } catch (e) { print('Error: $e'); } }
此示例展示了创建不可变 Map 的工厂模式。私有的 _UnmodifiableMapWrapper 类实现了不可变行为。
$ dart main.dart 20 true Error: Unsupported operation: Cannot modify unmodifiable map
具有自定义键值类型的不可变 Map
UnmodifiableMapBase 可与自定义类型一起使用,同时保持不可变性。
main.dart
import 'dart:collection'; class Product { final String id; final String name; Product(this.id, this.name); @override String toString() => 'Product($id, $name)'; } class UnmodifiableProductMap extends UnmodifiableMapBase<String, Product> { final Map<String, Product> _products; UnmodifiableProductMap(this._products); @override Product? operator [](Object? key) => _products[key]; @override Iterable<String> get keys => _products.keys; } void main() { final products = { 'p1': Product('p1', 'Laptop'), 'p2': Product('p2', 'Phone'), 'p3': Product('p3', 'Tablet') }; final unmodifiable = UnmodifiableProductMap(products); print(unmodifiable['p2']); // Product(p2, Phone) print(unmodifiable.values.where((p) => p.name.length > 5).toList()); try { unmodifiable['p4'] = Product('p4', 'Monitor'); // Throws } catch (e) { print('Modification error: $e'); } }
我们为 Product 对象创建了一个类型安全的不可变 Map。该 Map 提供只读访问,同时阻止对产品集合的任何修改。
$ dart main.dart Product(p2, Phone) [Product(p1, Laptop), Product(p3, Tablet)] Modification error: Unsupported operation: Cannot modify unmodifiable map
将 UnmodifiableMapBase 与其他集合结合使用
UnmodifiableMapBase 可以与其他集合类型结合使用,以创建复杂的不可变数据结构。
main.dart
import 'dart:collection'; class ImmutableConfig extends UnmodifiableMapBase<String, dynamic> { final Map<String, dynamic> _config; final List<String> _log; ImmutableConfig(this._config, this._log); @override dynamic operator [](Object? key) { _log.add('Accessed: $key'); return _config[key]; } @override Iterable<String> get keys => _config.keys; } void main() { final config = { 'timeout': 30, 'retries': 3, 'debug': false }; final accessLog = <String>[]; final immutableConfig = ImmutableConfig(config, accessLog); print(immutableConfig['timeout']); // 30 print(immutableConfig['debug']); // false try { immutableConfig['timeout'] = 60; // Throws } catch (e) { print('Error: $e'); } print('Access log: $accessLog'); }
此示例将一个不可变 Map 与一个日志列表结合使用。Map 保持不可变,同时跟踪访问尝试。日志列表可以单独访问。
$ dart main.dart 30 false Error: Unsupported operation: Cannot modify unmodifiable map Access log: [Accessed: timeout, Accessed: debug]
带懒加载的高级 UnmodifiableMapBase
我们可以通过重写访问器来实现不可变 Map 中的懒加载。
main.dart
import 'dart:collection'; class LazyUnmodifiableMap extends UnmodifiableMapBase<String, String> { final Map<String, String> _source; final Map<String, String> _cache = {}; LazyUnmodifiableMap(this._source); @override String? operator [](Object? key) { if (key is! String) return null; if (!_cache.containsKey(key)) { print('Loading $key from source...'); _cache[key] = _source[key] ?? 'DEFAULT'; } return _cache[key]; } @override Iterable<String> get keys => _source.keys; } void main() { final source = { 'config1': 'Value1', 'config2': 'Value2', 'config3': 'Value3' }; final lazyMap = LazyUnmodifiableMap(source); print('First access:'); print(lazyMap['config2']); // Loads and caches print('\nSecond access:'); print(lazyMap['config2']); // Uses cache print('\nAll keys:'); print(lazyMap.keys.join(', ')); try { lazyMap['new'] = 'value'; // Throws } catch (e) { print('\nError: $e'); } }
这个高级示例使用缓存实现了懒加载。值在第一次访问时加载,并在后续请求中缓存。Map 保持不可变。
$ dart main.dart First access: Loading config2 from source... Value2 Second access: Value2 All keys: config1, config2, config3 Error: Unsupported operation: Cannot modify unmodifiable map
最佳实践
- 不可变设计: 用于安全地公开内部状态。
- 性能: 考虑对昂贵的查找进行缓存。
- 类型安全: 为强类型创建特定子类。
- 文档: 清晰地记录不可变性。
- 组合: 与工厂等其他模式结合。
来源
本教程通过实际示例介绍了 Dart 的 UnmodifiableMapBase
,演示了不可变 Map 的实现和模式。
作者
列出 所有 Dart 教程。