Dart Set API 详细总结

58 阅读17分钟

Dart Set API 详细总结

基于Dart官方API文档与实践经验整理

目录

概述

在Dart中,Set是一个不包含重复元素的集合,类似于数学中的集合概念。Set具有以下特性:

  • 唯一性: 不允许重复元素
  • 无序性: 元素没有固定的顺序(除了LinkedHashSet)
  • 高效查找: 基于哈希表实现,查找效率高
  • 泛型支持: 支持类型安全的泛型操作
  • 集合运算: 支持并集、交集、差集等数学运算

创建Set

1. 字面量语法创建

// 创建包含初始值的Set
Set<int> numbers = {1, 2, 3, 4, 5};
Set<String> names = {'Alice', 'Bob', 'Charlie'};

// 创建空Set(需要指定类型)
Set<int> emptyNumbers = <int>{};
Set<String> emptyNames = <String>{};

// 类型推断
var fruits = {'apple', 'banana', 'orange'}; // Set<String>
var scores = {95, 87, 92}; // Set<int>

// 注意:空大括号{}创建的是Map,不是Set
var emptyMap = {}; // Map<dynamic, dynamic>
var emptySet = <String>{}; // Set<String>

创建Set使用注意事项

⚠️ 重要提醒:

  1. 空集合语法陷阱

    // ❌ 这创建的是Map,不是Set!
    var wrong = {}; // Map<dynamic, dynamic>
    
    // ✅ 正确的空Set创建方式
    var correctSet = <String>{};
    var anotherSet = Set<String>();
    
  2. 重复元素自动去重

    // 重复元素会被自动去除
    Set<int> numbers = {1, 2, 2, 3, 3, 3}; 
    print(numbers); // {1, 2, 3}
    

2. 构造函数创建

// 创建空Set
Set<int> emptySet = Set<int>();
// 参数: 无
// 返回: Set<E> - 新的空Set

// 从其他可迭代对象创建
Set<int> fromIterable = Set<int>.from([1, 2, 3, 2, 1]);
// 参数: elements (Iterable) - 源可迭代对象
// 返回: Set<E> - 新的Set,自动去重
// 结果: {1, 2, 3}

Set<int> ofIterable = Set<int>.of([1, 2, 3, 2, 1]);
// 参数: elements (Iterable<E>) - 源可迭代对象(类型安全)
// 返回: Set<E> - 新的Set,自动去重

// 创建不可变Set
Set<int> unmodifiableSet = Set.unmodifiable([1, 2, 3]);
// 参数: elements (Iterable<E>) - 源可迭代对象
// 返回: Set<E> - 不可修改的Set

// 创建身份Set(基于对象身份而非相等性)
Set<String> identitySet = Set<String>.identity();
// 参数: 无
// 返回: Set<E> - 基于身份比较的Set

构造函数使用注意事项

⚠️ 重要提醒:

  1. Set.from vs Set.of的区别

    dynamic dynamicList = [1, 2, 3];
    
    // Set.from 接受任意Iterable,可能有运行时类型错误
    Set<int> fromSet = Set<int>.from(dynamicList);
    
    // Set.of 要求类型匹配,编译时类型安全
    // Set<int> ofSet = Set<int>.of(dynamicList); // 编译错误
    Set<int> ofSet = Set<int>.of(<int>[1, 2, 3]); // 正确
    
  2. 身份Set vs 相等性Set

    Set<String> normalSet = {'hello', 'world'};
    Set<String> identitySet = Set.identity()..addAll(['hello', 'world']);
    
    String hello1 = 'hello';
    String hello2 = 'hello';
    
    print(normalSet.contains(hello1)); // true
    print(normalSet.contains(hello2)); // true - 基于值相等
    
    identitySet.clear();
    identitySet.add(hello1);
    print(identitySet.contains(hello1)); // true
    print(identitySet.contains(hello2)); // true - 字符串字面量共享引用
    
    // 对于对象更明显
    class Person {
      String name;
      Person(this.name);
    }
    
    Person p1 = Person('Alice');
    Person p2 = Person('Alice');
    
    Set<Person> normalPersonSet = {p1, p2}; // 可能包含两个Person(如果没有重写==)
    Set<Person> identityPersonSet = Set.identity()..addAll([p1, p2]); // 包含两个Person
    
  3. 不可变Set的限制

    Set<int> immutableSet = Set.unmodifiable([1, 2, 3]);
    
    // ❌ 这些操作都会抛出UnsupportedError
    // immutableSet.add(4);
    // immutableSet.remove(1);
    // immutableSet.clear();
    

基本属性

Set<String> fruits = {'apple', 'banana', 'orange'};

// 长度
print(fruits.length); // 3

// 是否为空
print(fruits.isEmpty); // false
print(fruits.isNotEmpty); // true

// 第一个和最后一个元素(注意:Set是无序的,这些值可能不确定)
print(fruits.first); // 可能是任意元素
print(fruits.last);  // 可能是任意元素

// 单个元素(当且仅当Set只有一个元素时)
Set<String> single = {'only'};
print(single.single); // 'only'

// 迭代器
Iterator<String> iterator = fruits.iterator;

基本属性使用注意事项

⚠️ 重要提醒:

  1. Set的无序性

    Set<int> numbers = {3, 1, 4, 1, 5}; // 注意:重复的1会被去除
    
    // ❌ 不要依赖Set中元素的顺序
    // print(numbers.first); // 结果不确定
    
    // ✅ 如果需要有序,使用LinkedHashSet或转换为List
    import 'dart:collection';
    LinkedHashSet<int> orderedSet = LinkedHashSet<int>.from([3, 1, 4, 1, 5]);
    print(orderedSet.first); // 3,保持插入顺序
    
  2. 空Set访问陷阱

    Set<String> emptySet = <String>{};
    
    // ❌ 这些都会抛出异常
    // print(emptySet.first);  // StateError
    // print(emptySet.last);   // StateError
    // print(emptySet.single); // StateError
    
    // ✅ 安全的访问方式
    if (emptySet.isNotEmpty) {
      print(emptySet.first);
    }
    

添加和删除元素

Set<int> numbers = {1, 2, 3};

// 添加单个元素
bool added = numbers.add(4);
// 参数: value (E) - 要添加的元素
// 返回: bool - 如果元素是新的返回true,如果已存在返回false
print(numbers); // {1, 2, 3, 4}
print(added); // true

// 尝试添加重复元素
bool duplicateAdded = numbers.add(3);
print(duplicateAdded); // false,元素已存在

// 添加多个元素
numbers.addAll([5, 6, 7, 3]); // 3已存在,不会重复添加
// 参数: elements (Iterable<E>) - 要添加的可迭代对象
// 返回: void
print(numbers); // {1, 2, 3, 4, 5, 6, 7}

// 删除单个元素
bool removed = numbers.remove(3);
// 参数: value (Object?) - 要删除的元素
// 返回: bool - 如果成功删除返回true,否则返回false
print(numbers); // {1, 2, 4, 5, 6, 7}
print(removed); // true

// 删除多个元素
numbers.removeAll([1, 2, 8, 9]); // 8, 9不存在,不会报错
// 参数: elements (Iterable<Object?>) - 要删除的可迭代对象
// 返回: void
print(numbers); // {4, 5, 6, 7}

// 只保留指定元素
numbers.retainAll([4, 5, 10, 11]); // 只保留存在的4, 5
// 参数: elements (Iterable<Object?>) - 要保留的可迭代对象
// 返回: void
print(numbers); // {4, 5}

// 根据条件删除
Set<int> values = {1, 2, 3, 4, 5, 6};
values.removeWhere((element) => element % 2 == 0);
// 参数: test (bool Function(E)) - 测试函数,返回true的元素将被删除
// 返回: void
print(values); // {1, 3, 5}

// 根据条件保留
Set<int> scores = {85, 92, 78, 96, 88};
scores.retainWhere((score) => score >= 90);
// 参数: test (bool Function(E)) - 测试函数,返回true的元素将被保留
// 返回: void
print(scores); // {92, 96}

// 清空Set
numbers.clear();
// 参数: 无
// 返回: void
print(numbers); // {}

添加删除使用注意事项

⚠️ 重要提醒:

  1. add方法的返回值意义

    Set<String> names = {'Alice', 'Bob'};
    
    bool result1 = names.add('Charlie'); // true - 新元素
    bool result2 = names.add('Alice');   // false - 已存在
    
    // ✅ 可以利用返回值判断元素是否已存在
    if (!names.add('David')) {
      print('David已经存在');
    }
    
  2. 删除不存在元素不会报错

    Set<int> numbers = {1, 2, 3};
    
    // ✅ 删除不存在的元素是安全的
    bool removed = numbers.remove(999); // false,但不会报错
    numbers.removeAll([4, 5, 6]); // 安全,不会报错
    
  3. 不可变Set的操作限制

    Set<int> immutableSet = Set.unmodifiable([1, 2, 3]);
    
    // ❌ 这些操作都会抛出UnsupportedError
    // immutableSet.add(4);
    // immutableSet.remove(1);
    // immutableSet.addAll([4, 5]);
    // immutableSet.removeAll([1, 2]);
    // immutableSet.clear();
    

查找和检查

Set<String> animals = {'cat', 'dog', 'bird'};

// 检查是否包含元素
print(animals.contains('dog')); // true
print(animals.contains('fish')); // false
// 参数: element (Object?) - 要查找的元素
// 返回: bool - 如果包含该元素返回true,否则返回false

// 检查是否包含任意指定元素
print(animals.containsAll(['cat', 'dog'])); // true
print(animals.containsAll(['cat', 'fish'])); // false
// 参数: other (Iterable<Object?>) - 要检查的元素集合
// 返回: bool - 如果包含所有指定元素返回true,否则返回false

// 查找符合条件的元素
String? found = animals.firstWhere(
  (animal) => animal.startsWith('b'),
  orElse: () => 'not found'
);
// 参数: 
//   test (bool Function(E)) - 测试函数
//   orElse (E Function()?, 可选) - 未找到时的默认值函数
// 返回: E - 第一个符合条件的元素
print(found); // 'bird'

// 查找符合条件的元素(可能为null)
String? foundOrNull = animals.cast<String?>().firstWhere(
  (animal) => animal?.startsWith('z') ?? false,
  orElse: () => null
);
print(foundOrNull); // null

// 检查所有元素是否符合条件
Set<int> numbers = {2, 4, 6, 8};
print(numbers.every((n) => n % 2 == 0)); // true
// 参数: test (bool Function(E)) - 测试函数
// 返回: bool - 如果所有元素都符合条件返回true,否则返回false

// 检查是否有元素符合条件
Set<int> mixed = {1, 3, 5, 6};
print(mixed.any((n) => n % 2 == 0)); // true
// 参数: test (bool Function(E)) - 测试函数
// 返回: bool - 如果至少有一个元素符合条件返回true,否则返回false

// 查找元素(返回元素本身或null)
String? lookup = animals.lookup('cat');
// 参数: object (Object?) - 要查找的对象
// 返回: E? - 如果找到返回Set中的元素,否则返回null
print(lookup); // 'cat'

String? notFound = animals.lookup('fish');
print(notFound); // null

查找检查使用注意事项

⚠️ 重要提醒:

  1. contains vs lookup的区别

    Set<String> names = {'Alice', 'Bob'};
    
    // contains只返回bool值
    bool hasAlice = names.contains('Alice'); // true
    
    // lookup返回实际的元素,可用于获取Set中的对象
    String? actualAlice = names.lookup('Alice'); // 'Alice'
    
    // 对于自定义对象,lookup很有用
    class Person {
      String name;
      int age;
      Person(this.name, this.age);
      
      @override
      bool operator ==(Object other) => 
          other is Person && other.name == name;
      
      @override
      int get hashCode => name.hashCode;
    }
    
    Set<Person> people = {Person('Alice', 25), Person('Bob', 30)};
    Person? found = people.lookup(Person('Alice', 999)); // 找到age=25的Alice
    
  2. firstWhere的异常处理

    Set<int> numbers = {1, 3, 5};
    
    // ❌ 没有orElse时,未找到会抛出StateError
    try {
      int even = numbers.firstWhere((n) => n % 2 == 0);
    } catch (e) {
      print('未找到偶数: $e');
    }
    
    // ✅ 提供orElse避免异常
    int evenOrDefault = numbers.firstWhere(
      (n) => n % 2 == 0,
      orElse: () => -1
    );
    
  3. 空Set的边界情况

    Set<int> emptySet = <int>{};
    
    // ✅ 这些方法在空Set上是安全的
    print(emptySet.contains(1));          // false
    print(emptySet.containsAll([1, 2]));  // false
    print(emptySet.every((x) => x > 0));  // true! 空集合的全称量词为真
    print(emptySet.any((x) => x > 0));    // false
    

集合运算

Set<int> set1 = {1, 2, 3, 4};
Set<int> set2 = {3, 4, 5, 6};
Set<int> set3 = {4, 5, 6, 7};

// 并集(union)- 包含两个集合的所有元素
Set<int> unionResult = set1.union(set2);
// 参数: other (Set<E>) - 另一个集合
// 返回: Set<E> - 新的包含两个集合所有元素的Set
print(unionResult); // {1, 2, 3, 4, 5, 6}

// 交集(intersection)- 包含两个集合的共同元素
Set<int> intersectionResult = set1.intersection(set2);
// 参数: other (Set<Object?>) - 另一个集合
// 返回: Set<E> - 新的包含共同元素的Set
print(intersectionResult); // {3, 4}

// 差集(difference)- 包含在第一个集合但不在第二个集合中的元素
Set<int> differenceResult = set1.difference(set2);
// 参数: other (Set<Object?>) - 另一个集合
// 返回: Set<E> - 新的包含差集元素的Set
print(differenceResult); // {1, 2}

// 多个集合的运算
Set<int> multiUnion = set1.union(set2).union(set3);
print(multiUnion); // {1, 2, 3, 4, 5, 6, 7}

Set<int> multiIntersection = set1.intersection(set2).intersection(set3);
print(multiIntersection); // {4}

集合运算使用注意事项

⚠️ 重要提醒:

  1. 集合运算返回新Set

    Set<int> original = {1, 2, 3};
    Set<int> other = {2, 3, 4};
    
    Set<int> result = original.union(other);
    
    // ✅ 原始集合不会被修改
    print(original); // {1, 2, 3} - 保持不变
    print(result);   // {1, 2, 3, 4} - 新的集合
    
  2. 空集合的运算规律

    Set<int> numbers = {1, 2, 3};
    Set<int> empty = <int>{};
    
    print(numbers.union(empty));        // {1, 2, 3} - 并集
    print(numbers.intersection(empty)); // {} - 交集为空
    print(numbers.difference(empty));   // {1, 2, 3} - 差集是原集合
    print(empty.difference(numbers));   // {} - 空集合的差集为空
    
  3. 类型兼容性

    Set<int> integers = {1, 2, 3};
    Set<num> numbers = {2.5, 3, 4};
    
    // ✅ 可以与超类型进行运算
    Set<int> result = integers.intersection(numbers); // {3}
    
    // ❌ 但要注意类型安全
    // Set<int> badResult = integers.union(numbers); // 类型错误
    

转换和映射

Set<int> numbers = {1, 2, 3, 4, 5};

// map: 转换每个元素
Set<int> doubled = numbers.map((n) => n * 2).toSet();
// 参数: f (T Function(E)) - 转换函数,接收元素返回转换后的值
// 返回: Iterable<T> - 转换后的可迭代对象(需要toSet()转换为Set)
print(doubled); // {2, 4, 6, 8, 10}

// where: 过滤元素
Set<int> evenNumbers = numbers.where((n) => n % 2 == 0).toSet();
// 参数: test (bool Function(E)) - 测试函数,返回true的元素将被保留
// 返回: Iterable<E> - 过滤后的可迭代对象
print(evenNumbers); // {2, 4}

// expand: 展开元素
Set<List<int>> nested = {{1, 2}, {3, 4}, {5}};
Set<int> flattened = nested.expand((set) => set).toSet();
// 参数: f (Iterable<T> Function(E)) - 展开函数,接收元素返回可迭代对象
// 返回: Iterable<T> - 展开后的可迭代对象
print(flattened); // {1, 2, 3, 4, 5}

// fold: 累积操作
int sum = numbers.fold(0, (prev, element) => prev + element);
// 参数: 
//   initialValue (T) - 初始值
//   combine (T Function(T, E)) - 累积函数,接收前一个值和当前元素
// 返回: T - 累积结果
print(sum); // 15

// reduce: 归约操作
int product = numbers.reduce((value, element) => value * element);
// 参数: combine (E Function(E, E)) - 归约函数,接收两个元素返回归约结果
// 返回: E - 归约结果
// 注意: 如果Set为空会抛出异常
print(product); // 120

// 转换为其他集合类型
List<int> numbersList = numbers.toList();
// 参数: 无
// 返回: List<E> - 转换后的List
print(numbersList); // [1, 2, 3, 4, 5] (顺序可能不同)

// 转换为字符串
String setString = numbers.join(', ');
// 参数: separator (String, 可选) - 分隔符,默认为空字符串
// 返回: String - 连接后的字符串
print(setString); // "1, 2, 3, 4, 5" (顺序可能不同)

转换映射使用注意事项

⚠️ 重要提醒:

  1. map操作可能产生重复元素

    Set<int> numbers = {1, 2, 3, 4, 5};
    
    // ❌ map后可能有重复元素
    Iterable<int> halves = numbers.map((n) => n ~/ 2); // [0, 1, 1, 2, 2]
    Set<int> uniqueHalves = halves.toSet(); // {0, 1, 2} - 自动去重
    
    print(halves.length);       // 5
    print(uniqueHalves.length); // 3
    
  2. 惰性求值的注意事项

    Set<int> numbers = {1, 2, 3, 4, 5};
    
    // ❌ 这些操作是惰性的,不会立即执行
    Iterable<int> doubled = numbers.map((n) => n * 2);
    Iterable<int> evens = numbers.where((n) => n % 2 == 0);
    
    // ✅ 需要调用toSet()或toList()才会实际执行
    Set<int> doubledSet = numbers.map((n) => n * 2).toSet();
    Set<int> evensSet = numbers.where((n) => n % 2 == 0).toSet();
    
  3. reduce在空Set上的异常

    Set<int> numbers = {1, 2, 3, 4, 5};
    Set<int> emptySet = <int>{};
    
    // ✅ fold可以处理空Set
    int sum1 = numbers.fold(0, (a, b) => a + b); // 15
    int sum2 = emptySet.fold(0, (a, b) => a + b); // 0
    
    // ❌ reduce在空Set上会抛出异常
    int sum3 = numbers.reduce((a, b) => a + b); // 15
    // int sum4 = emptySet.reduce((a, b) => a + b); // StateError!
    
    // ✅ 安全的reduce使用
    if (emptySet.isNotEmpty) {
      int sum = emptySet.reduce((a, b) => a + b);
    }
    

高级操作

类型转换和过滤

Set<dynamic> mixed = {1, 'hello', 2, 'world', 3.14, true};

// 类型过滤
Set<int> integers = mixed.whereType<int>().toSet();
// 参数: 无(泛型参数指定类型)
// 返回: Iterable<T> - 指定类型的元素
print(integers); // {1, 2}

Set<String> strings = mixed.whereType<String>().toSet();
print(strings); // {'hello', 'world'}

// 类型转换
Set<String> stringified = mixed.map((e) => e.toString()).toSet();
print(stringified); // {'1', 'hello', '2', 'world', '3.14', 'true'}

集合比较

Set<int> set1 = {1, 2, 3};
Set<int> set2 = {1, 2, 3};
Set<int> set3 = {3, 2, 1}; // 顺序不同
Set<int> set4 = {1, 2, 3, 4};

// Set相等性比较(基于内容,不考虑顺序)
print(set1 == set2); // true
print(set1 == set3); // true - Set不考虑顺序
print(set1 == set4); // false

// 检查子集关系
bool isSubset(Set<E> subset, Set<E> superset) {
  return subset.difference(superset).isEmpty;
}

bool isSupersetOf(Set<E> superset, Set<E> subset) {
  return subset.difference(superset).isEmpty;
}

print(isSubset(set1, set4)); // true - set1是set4的子集
print(isSupersetOf(set4, set1)); // true - set4是set1的超集

自定义Set实现

import 'dart:collection';

// LinkedHashSet - 保持插入顺序
LinkedHashSet<String> orderedSet = LinkedHashSet<String>();
orderedSet.addAll(['third', 'first', 'second']);
print(orderedSet.toList()); // [third, first, second] - 保持插入顺序

// SplayTreeSet - 自动排序
SplayTreeSet<int> sortedSet = SplayTreeSet<int>();
sortedSet.addAll([3, 1, 4, 1, 5, 9]);
print(sortedSet.toList()); // [1, 3, 4, 5, 9] - 自动排序且去重

// 自定义比较器的SplayTreeSet
SplayTreeSet<String> customSortedSet = SplayTreeSet<String>(
  (a, b) => b.compareTo(a) // 反向排序
);
customSortedSet.addAll(['banana', 'apple', 'cherry']);
print(customSortedSet.toList()); // [cherry, banana, apple]

高级操作使用注意事项

⚠️ 重要提醒:

  1. 不同Set实现的性能特点

    // HashSet - 最快的查找,无序
    Set<int> hashSet = <int>{}; // 默认实现
    
    // LinkedHashSet - 保持插入顺序,稍慢
    import 'dart:collection';
    LinkedHashSet<int> linkedSet = LinkedHashSet<int>();
    
    // SplayTreeSet - 自动排序,查找O(log n)
    SplayTreeSet<int> treeSet = SplayTreeSet<int>();
    
    // 性能对比(大概):
    // 插入: HashSet > LinkedHashSet > SplayTreeSet
    // 查找: HashSet ≈ LinkedHashSet > SplayTreeSet
    // 遍历: 都是O(n),但SplayTreeSet是有序的
    
  2. 自定义对象的哈希和相等性

    class Person {
      String name;
      int age;
      Person(this.name, this.age);
      
      // ✅ 必须同时重写==和hashCode
      @override
      bool operator ==(Object other) =>
          other is Person && other.name == name && other.age == age;
      
      @override
      int get hashCode => Object.hash(name, age);
      
      @override
      String toString() => 'Person($name, $age)';
    }
    
    Set<Person> people = {
      Person('Alice', 25),
      Person('Bob', 30),
      Person('Alice', 25), // 重复,会被去除
    };
    print(people.length); // 2
    
  3. 类型过滤的安全性

    Set<dynamic> mixed = {1, 'hello', null, 2.5};
    
    // ✅ whereType是安全的
    Set<int> integers = mixed.whereType<int>().toSet();
    
    // ❌ 强制转换可能出错
    // Set<int> forced = mixed.map((e) => e as int).toSet(); // 运行时错误!
    
    // ✅ 安全的转换
    Set<int> safe = mixed
        .where((e) => e is int)
        .map((e) => e as int)
        .toSet();
    

方法参数速查表

构造方法

方法参数说明返回值
Set()创建空SetSet<E>
Set.from()elements: Iterable从可迭代对象创建Set<E>
Set.of()elements: Iterable<E>从可迭代对象创建(类型安全)Set<E>
Set.unmodifiable()elements: Iterable<E>创建不可修改SetSet<E>
Set.identity()创建基于身份比较的SetSet<E>

添加删除方法

方法参数说明返回值
add()value: E添加元素bool
addAll()elements: Iterable<E>添加多个元素void
remove()value: Object?删除元素bool
removeAll()elements: Iterable<Object?>删除多个元素void
retainAll()elements: Iterable<Object?>只保留指定元素void
removeWhere()test: bool Function(E)根据条件删除void
retainWhere()test: bool Function(E)根据条件保留void
clear()清空Setvoid

查找检查方法

方法参数说明返回值
contains()element: Object?检查是否包含元素bool
containsAll()other: Iterable<Object?>检查是否包含所有元素bool
lookup()object: Object?查找元素E?
firstWhere()test: bool Function(E) orElse: E Function()?查找符合条件的元素E
every()test: bool Function(E)检查所有元素是否符合条件bool
any()test: bool Function(E)检查是否有元素符合条件bool

集合运算方法

方法参数说明返回值
union()other: Set<E>并集运算Set<E>
intersection()other: Set<Object?>交集运算Set<E>
difference()other: Set<Object?>差集运算Set<E>

转换映射方法

方法参数说明返回值
map()f: T Function(E)转换每个元素Iterable<T>
where()test: bool Function(E)过滤元素Iterable<E>
whereType()无(泛型参数)类型过滤Iterable<T>
expand()f: Iterable<T> Function(E)展开元素Iterable<T>
fold()initialValue: T combine: T Function(T, E)累积操作T
reduce()combine: E Function(E, E)归约操作E
join()separator: String转换为字符串String
toList()转换为ListList<E>

性能考虑

时间复杂度详解

操作HashSetLinkedHashSetSplayTreeSet说明
add()O(1)*O(1)*O(log n)*摊销时间,最坏O(n)
remove()O(1)*O(1)*O(log n)*摊销时间,最坏O(n)
contains()O(1)*O(1)*O(log n)查找操作
lookup()O(1)*O(1)*O(log n)查找并返回元素
clear()O(n)O(n)O(n)清空所有元素
union()O(n+m)O(n+m)O(n log m + m log n)n,m为两个集合大小
intersection()O(min(n,m))O(min(n,m))O(n log m)取较小集合遍历
difference()O(n)O(n)O(n log m)n为第一个集合大小
遍历O(n)O(n)O(n)线性遍历
排序输出O(n log n)O(n log n)O(n)TreeSet已排序

*摊销时间复杂度,哈希冲突时可能退化

空间复杂度

Set类型空间复杂度额外开销说明
HashSetO(n)~25-50%哈希表空间,负载因子影响
LinkedHashSetO(n)~50-75%额外的链表指针
SplayTreeSetO(n)~100%树节点指针开销

性能基准测试

import 'dart:collection';
import 'dart:math';

/// 性能测试工具类
class SetPerformanceTester {
  static const int testSize = 100000;
  static final Random _random = Random();
  
  /// 测试不同Set实现的插入性能
  static void testInsertPerformance() {
    print('=== 插入性能测试 (${testSize}个元素) ===');
    
    // 生成测试数据
    List<int> testData = List.generate(testSize, (i) => _random.nextInt(testSize * 2));
    
    // HashSet测试
    Stopwatch sw = Stopwatch()..start();
    Set<int> hashSet = <int>{};
    for (int value in testData) {
      hashSet.add(value);
    }
    sw.stop();
    print('HashSet插入: ${sw.elapsedMilliseconds}ms, 元素数: ${hashSet.length}');
    
    // LinkedHashSet测试
    sw.reset()..start();
    LinkedHashSet<int> linkedSet = LinkedHashSet<int>();
    for (int value in testData) {
      linkedSet.add(value);
    }
    sw.stop();
    print('LinkedHashSet插入: ${sw.elapsedMilliseconds}ms, 元素数: ${linkedSet.length}');
    
    // SplayTreeSet测试
    sw.reset()..start();
    SplayTreeSet<int> treeSet = SplayTreeSet<int>();
    for (int value in testData) {
      treeSet.add(value);
    }
    sw.stop();
    print('SplayTreeSet插入: ${sw.elapsedMilliseconds}ms, 元素数: ${treeSet.length}');
  }
  
  /// 测试查找性能
  static void testLookupPerformance() {
    print('\n=== 查找性能测试 ===');
    
    // 准备数据
    List<int> data = List.generate(testSize, (i) => i);
    Set<int> hashSet = data.toSet();
    LinkedHashSet<int> linkedSet = LinkedHashSet.from(data);
    SplayTreeSet<int> treeSet = SplayTreeSet.from(data);
    
    // 生成查找目标
    List<int> searchTargets = List.generate(10000, (i) => _random.nextInt(testSize));
    
    // HashSet查找
    Stopwatch sw = Stopwatch()..start();
    int found = 0;
    for (int target in searchTargets) {
      if (hashSet.contains(target)) found++;
    }
    sw.stop();
    print('HashSet查找: ${sw.elapsedMilliseconds}ms, 找到: $found');
    
    // LinkedHashSet查找
    sw.reset()..start();
    found = 0;
    for (int target in searchTargets) {
      if (linkedSet.contains(target)) found++;
    }
    sw.stop();
    print('LinkedHashSet查找: ${sw.elapsedMilliseconds}ms, 找到: $found');
    
    // SplayTreeSet查找
    sw.reset()..start();
    found = 0;
    for (int target in searchTargets) {
      if (treeSet.contains(target)) found++;
    }
    sw.stop();
    print('SplayTreeSet查找: ${sw.elapsedMilliseconds}ms, 找到: $found');
  }
  
  /// 测试集合运算性能
  static void testSetOperationsPerformance() {
    print('\n=== 集合运算性能测试 ===');
    
    Set<int> set1 = Set.from(List.generate(testSize ~/ 2, (i) => i));
    Set<int> set2 = Set.from(List.generate(testSize ~/ 2, (i) => i + testSize ~/ 4));
    
    // 并集测试
    Stopwatch sw = Stopwatch()..start();
    Set<int> unionResult = set1.union(set2);
    sw.stop();
    print('并集运算: ${sw.elapsedMilliseconds}ms, 结果大小: ${unionResult.length}');
    
    // 交集测试
    sw.reset()..start();
    Set<int> intersectionResult = set1.intersection(set2);
    sw.stop();
    print('交集运算: ${sw.elapsedMilliseconds}ms, 结果大小: ${intersectionResult.length}');
    
    // 差集测试
    sw.reset()..start();
    Set<int> differenceResult = set1.difference(set2);
    sw.stop();
    print('差集运算: ${sw.elapsedMilliseconds}ms, 结果大小: ${differenceResult.length}');
  }
}

内存使用优化

1. 选择合适的初始容量
/// 内存优化的Set创建
class OptimizedSetCreation {
  /// 根据预期大小创建HashSet
  static Set<T> createOptimalHashSet<T>(int expectedSize) {
    // Dart的HashSet会自动调整大小,但预估有助于减少rehashing
    if (expectedSize <= 100) {
      return <T>{}; // 小集合使用默认
    } else if (expectedSize <= 10000) {
      // 中等大小集合,可以考虑预分配
      return <T>{};
    } else {
      // 大集合,考虑分批处理
      return <T>{};
    }
  }
  
  /// 内存敏感的大集合处理
  static Set<T> createLargeSet<T>(Iterable<T> source) {
    Set<T> result = <T>{};
    
    // 分批添加,避免一次性分配大量内存
    const int batchSize = 1000;
    List<T> batch = [];
    
    for (T item in source) {
      batch.add(item);
      if (batch.length >= batchSize) {
        result.addAll(batch);
        batch.clear(); // 及时释放临时内存
      }
    }
    
    if (batch.isNotEmpty) {
      result.addAll(batch);
    }
    
    return result;
  }
}
2. 内存泄漏防护
/// 防止内存泄漏的Set管理
class MemorySafeSetManager<T> {
  Set<T> _items = <T>{};
  static const int maxSize = 10000;
  
  /// 安全添加元素,防止无限增长
  bool add(T item) {
    if (_items.length >= maxSize) {
      // 实现LRU策略或简单清理
      _clearOldest();
    }
    return _items.add(item);
  }
  
  /// 清理最旧的元素(简化版LRU)
  void _clearOldest() {
    if (_items.isNotEmpty) {
      // 简单策略:清理一半元素
      List<T> itemsList = _items.toList();
      _items.clear();
      _items.addAll(itemsList.skip(itemsList.length ~/ 2));
    }
  }
  
  /// 定期清理
  void periodicCleanup() {
    if (_items.length > maxSize * 0.8) {
      _clearOldest();
    }
  }
  
  /// 释放资源
  void dispose() {
    _items.clear();
  }
}

高级性能优化技巧

1. 哈希函数优化
/// 优化的自定义对象哈希实现
class OptimizedPerson {
  final String name;
  final int age;
  final String email;
  
  // 缓存哈希值,避免重复计算
  int? _cachedHashCode;
  
  OptimizedPerson(this.name, this.age, this.email);
  
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is OptimizedPerson &&
      runtimeType == other.runtimeType &&
      name == other.name &&
      age == other.age &&
      email == other.email;
  
  @override
  int get hashCode {
    // 使用缓存的哈希值
    return _cachedHashCode ??= Object.hash(name, age, email);
  }
  
  /// 高性能哈希实现(如果字段较多)
  static int fastHash(String name, int age, String email) {
    // 使用位运算优化哈希计算
    int hash = name.hashCode;
    hash = hash * 31 + age;
    hash = hash * 31 + email.hashCode;
    return hash;
  }
}

/// 针对特定场景的高性能哈希
class FastIntPair {
  final int x, y;
  
  const FastIntPair(this.x, this.y);
  
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is FastIntPair && x == other.x && y == other.y;
  
  @override
  int get hashCode {
    // 使用位移操作快速计算哈希
    return (x << 16) ^ y;
  }
}
2. 批量操作优化
/// 高效的批量Set操作
extension SetBatchOperations<T> on Set<T> {
  /// 高效的批量添加
  void addAllOptimized(Iterable<T> elements) {
    if (elements.isEmpty) return;
    
    // 对于大量元素,分批处理以避免内存峰值
    if (elements.length > 1000) {
      const int batchSize = 1000;
      Iterator<T> iterator = elements.iterator;
      
      while (iterator.moveNext()) {
        Set<T> batch = <T>{};
        batch.add(iterator.current);
        
        // 收集一批元素
        for (int i = 1; i < batchSize && iterator.moveNext(); i++) {
          batch.add(iterator.current);
        }
        
        // 批量添加
        addAll(batch);
      }
    } else {
      addAll(elements);
    }
  }
  
  /// 高效的条件批量删除
  void removeWhereOptimized(bool Function(T) test) {
    // 先收集要删除的元素,避免迭代时修改
    List<T> toRemove = where(test).toList();
    
    // 批量删除
    if (toRemove.isNotEmpty) {
      removeAll(toRemove);
    }
  }
  
  /// 高效的集合运算
  Set<T> unionOptimized(Set<T> other) {
    // 优化:总是以较大的集合为基础
    if (length >= other.length) {
      return Set<T>.from(this)..addAll(other);
    } else {
      return Set<T>.from(other)..addAll(this);
    }
  }
  
  Set<T> intersectionOptimized(Set<T> other) {
    // 优化:遍历较小的集合
    Set<T> smaller = length <= other.length ? this : other;
    Set<T> larger = length <= other.length ? other : this;
    
    return smaller.where(larger.contains).toSet();
  }
}
3. 并发安全的Set操作
import 'dart:async';

/// 线程安全的Set包装器
class ConcurrentSet<T> {
  final Set<T> _set = <T>{};
  final Completer<void>? _lock = null; // 简化示例
  
  /// 线程安全的添加操作
  Future<bool> add(T value) async {
    // 在实际应用中需要使用适当的同步机制
    return _set.add(value);
  }
  
  /// 线程安全的查询操作
  bool contains(T value) {
    return _set.contains(value);
  }
  
  /// 获取快照,避免并发修改
  Set<T> snapshot() {
    return Set<T>.from(_set);
  }
}

性能监控和调试

1. 性能分析工具
/// Set性能监控工具
class SetPerformanceMonitor<T> {
  final Set<T> _set;
  int _addCount = 0;
  int _removeCount = 0;
  int _lookupCount = 0;
  final Stopwatch _totalTime = Stopwatch();
  
  SetPerformanceMonitor(this._set);
  
  bool add(T value) {
    _totalTime.start();
    _addCount++;
    bool result = _set.add(value);
    _totalTime.stop();
    return result;
  }
  
  bool remove(T value) {
    _totalTime.start();
    _removeCount++;
    bool result = _set.remove(value);
    _totalTime.stop();
    return result;
  }
  
  bool contains(T value) {
    _totalTime.start();
    _lookupCount++;
    bool result = _set.contains(value);
    _totalTime.stop();
    return result;
  }
  
  /// 获取性能统计
  void printStats() {
    print('Set性能统计:');
    print('  总操作时间: ${_totalTime.elapsedMilliseconds}ms');
    print('  添加操作: $_addCount 次');
    print('  删除操作: $_removeCount 次');
    print('  查找操作: $_lookupCount 次');
    print('  当前大小: ${_set.length}');
    print('  平均操作时间: ${_totalTime.elapsedMicroseconds / (_addCount + _removeCount + _lookupCount)}μs');
  }
}
2. 内存使用分析
/// 内存使用分析工具
class SetMemoryAnalyzer {
  /// 估算Set的内存使用
  static int estimateMemoryUsage<T>(Set<T> set) {
    int baseSize = 0;
    
    // 基础开销估算
    if (set is LinkedHashSet) {
      baseSize = set.length * 24; // 估算:每个元素额外的指针开销
    } else if (set.runtimeType.toString().contains('SplayTree')) {
      baseSize = set.length * 32; // 估算:树节点开销
    } else {
      baseSize = set.length * 16; // 估算:哈希表开销
    }
    
    // 元素内容大小(简化估算)
    int contentSize = 0;
    if (set.isNotEmpty) {
      T sample = set.first;
      if (sample is String) {
        contentSize = set.cast<String>().fold(0, (sum, s) => sum + s.length * 2);
      } else if (sample is int) {
        contentSize = set.length * 8;
      } else {
        contentSize = set.length * 8; // 引用大小
      }
    }
    
    return baseSize + contentSize;
  }
  
  /// 分析不同Set实现的内存效率
  static void compareMemoryEfficiency<T>(Iterable<T> data) {
    print('=== 内存效率对比 ===');
    
    Set<T> hashSet = data.toSet();
    LinkedHashSet<T> linkedSet = LinkedHashSet.from(data);
    SplayTreeSet<T> treeSet = SplayTreeSet.from(data);
    
    print('数据量: ${data.length}');
    print('HashSet内存估算: ${estimateMemoryUsage(hashSet)} bytes');
    print('LinkedHashSet内存估算: ${estimateMemoryUsage(linkedSet)} bytes');
    print('SplayTreeSet内存估算: ${estimateMemoryUsage(treeSet)} bytes');
  }
}

实际应用场景的性能优化

1. 缓存系统优化
/// 高性能缓存Set
class PerformanceCache<T> {
  final Set<T> _cache = <T>{};
  final int maxSize;
  int _accessCount = 0;
  
  PerformanceCache({this.maxSize = 1000});
  
  bool add(T item) {
    _accessCount++;
    
    // 定期清理,避免频繁检查
    if (_accessCount % 100 == 0 && _cache.length > maxSize) {
      _performCleanup();
    }
    
    return _cache.add(item);
  }
  
  void _performCleanup() {
    // 简单的清理策略:保留一半元素
    if (_cache.length > maxSize) {
      List<T> items = _cache.toList();
      _cache.clear();
      _cache.addAll(items.take(maxSize ~/ 2));
    }
  }
  
  bool contains(T item) => _cache.contains(item);
  
  void clear() {
    _cache.clear();
    _accessCount = 0;
  }
}
2. 数据去重优化
/// 高效的数据去重工具
class DataDeduplicator<T> {
  /// 内存效率优先的去重
  static Set<T> deduplicateMemoryEfficient<T>(Iterable<T> data) {
    Set<T> result = <T>{};
    
    for (T item in data) {
      result.add(item);
      
      // 定期检查内存使用,防止内存爆炸
      if (result.length % 10000 == 0) {
        // 在实际应用中可以添加内存检查逻辑
        print('当前去重数据量: ${result.length}');
      }
    }
    
    return result;
  }
  
  /// 速度优先的去重
  static Set<T> deduplicateSpeedOptimized<T>(List<T> data) {
    // 预估大小,减少rehashing
    Set<T> result = <T>{};
    
    // 批量处理
    const int batchSize = 1000;
    for (int i = 0; i < data.length; i += batchSize) {
      int end = (i + batchSize > data.length) ? data.length : i + batchSize;
      result.addAll(data.sublist(i, end));
    }
    
    return result;
  }
}

性能测试和基准

/// 运行完整的性能测试套件
void runPerformanceTestSuite() {
  print('开始Set性能测试套件...\n');
  
  // 插入性能测试
  SetPerformanceTester.testInsertPerformance();
  
  // 查找性能测试
  SetPerformanceTester.testLookupPerformance();
  
  // 集合运算性能测试
  SetPerformanceTester.testSetOperationsPerformance();
  
  // 内存效率测试
  List<int> testData = List.generate(10000, (i) => i);
  SetMemoryAnalyzer.compareMemoryEfficiency(testData);
  
  print('\n性能测试完成!');
}

性能优化最佳实践总结

  1. 选择合适的Set实现

    • 频繁查找:使用HashSet
    • 需要保持顺序:使用LinkedHashSet
    • 需要排序:使用SplayTreeSet
  2. 优化哈希函数

    • 缓存哈希值避免重复计算
    • 使用高效的哈希算法
    • 确保哈希分布均匀
  3. 批量操作优化

    • 使用addAll而不是循环add
    • 分批处理大量数据
    • 预估集合大小
  4. 内存管理

    • 及时清理不需要的元素
    • 限制集合最大大小
    • 监控内存使用情况
  5. 并发安全

    • 使用适当的同步机制
    • 获取快照避免并发修改
    • 考虑使用不可变Set

通过这些优化技巧,可以显著提升Set操作的性能和内存效率。

性能分析和调试指南

1. 使用Dart Observatory进行性能分析
/// 性能分析示例代码
import 'dart:developer' as developer;

class SetProfiler<T> {
  final Set<T> _set;
  final String _name;
  
  SetProfiler(this._set, this._name);
  
  /// 带性能标记的添加操作
  bool addWithProfiling(T value) {
    return developer.Timeline.timeSync('$_name.add', () {
      return _set.add(value);
    });
  }
  
  /// 带性能标记的查找操作
  bool containsWithProfiling(T value) {
    return developer.Timeline.timeSync('$_name.contains', () {
      return _set.contains(value);
    });
  }
  
  /// 带性能标记的集合运算
  Set<T> unionWithProfiling(Set<T> other) {
    return developer.Timeline.timeSync('$_name.union', () {
      return _set.union(other);
    });
  }
}

/// 使用示例
void profileSetOperations() {
  Set<int> testSet = <int>{};
  SetProfiler<int> profiler = SetProfiler(testSet, 'TestSet');
  
  // 这些操作会在Dart Observatory中显示时间线
  for (int i = 0; i < 10000; i++) {
    profiler.addWithProfiling(i);
  }
  
  for (int i = 0; i < 1000; i++) {
    profiler.containsWithProfiling(i * 10);
  }
}
2. 内存使用监控
import 'dart:io';

/// 内存使用监控工具
class MemoryMonitor {
  static void logMemoryUsage(String operation) {
    ProcessInfo info = ProcessInfo.currentRss;
    int memoryMB = info ~/ (1024 * 1024);
    print('[$operation] 当前内存使用: ${memoryMB}MB');
  }
  
  /// 监控Set操作的内存影响
  static void monitorSetMemory<T>(Set<T> set, String setName) {
    print('=== $setName 内存监控 ===');
    logMemoryUsage('初始状态');
    
    // 模拟大量数据添加
    List<T> testData = _generateTestData<T>(100000);
    logMemoryUsage('测试数据生成完成');
    
    set.addAll(testData);
    logMemoryUsage('添加${testData.length}个元素后');
    
    // 清理一半数据
    List<T> toRemove = set.take(set.length ~/ 2).toList();
    set.removeAll(toRemove);
    logMemoryUsage('删除${toRemove.length}个元素后');
    
    set.clear();
    logMemoryUsage('清空Set后');
  }
  
  static List<T> _generateTestData<T>(int count) {
    if (T == int) {
      return List.generate(count, (i) => i).cast<T>();
    } else if (T == String) {
      return List.generate(count, (i) => 'item_$i').cast<T>();
    }
    throw UnsupportedError('不支持的类型: $T');
  }
}
3. 性能基准测试框架
/// 性能基准测试框架
class SetBenchmark<T> {
  final String name;
  final Set<T> Function() setFactory;
  final List<T> testData;
  
  SetBenchmark(this.name, this.setFactory, this.testData);
  
  /// 运行完整的性能基准测试
  BenchmarkResult runBenchmark() {
    BenchmarkResult result = BenchmarkResult(name);
    
    // 插入性能测试
    result.insertTime = _benchmarkInsert();
    
    // 查找性能测试
    result.lookupTime = _benchmarkLookup();
    
    // 删除性能测试
    result.removeTime = _benchmarkRemove();
    
    // 内存使用估算
    result.memoryUsage = _estimateMemoryUsage();
    
    return result;
  }
  
  int _benchmarkInsert() {
    Set<T> set = setFactory();
    Stopwatch sw = Stopwatch()..start();
    
    for (T item in testData) {
      set.add(item);
    }
    
    sw.stop();
    return sw.elapsedMicroseconds;
  }
  
  int _benchmarkLookup() {
    Set<T> set = setFactory();
    set.addAll(testData);
    
    Stopwatch sw = Stopwatch()..start();
    
    for (T item in testData.take(1000)) {
      set.contains(item);
    }
    
    sw.stop();
    return sw.elapsedMicroseconds;
  }
  
  int _benchmarkRemove() {
    Set<T> set = setFactory();
    set.addAll(testData);
    
    List<T> toRemove = testData.take(testData.length ~/ 2).toList();
    Stopwatch sw = Stopwatch()..start();
    
    for (T item in toRemove) {
      set.remove(item);
    }
    
    sw.stop();
    return sw.elapsedMicroseconds;
  }
  
  int _estimateMemoryUsage() {
    Set<T> set = setFactory();
    set.addAll(testData);
    
    // 简化的内存估算
    int baseSize = set.length * 16; // 基础开销
    int contentSize = 0;
    
    if (testData.isNotEmpty) {
      T sample = testData.first;
      if (sample is String) {
        contentSize = testData.cast<String>().fold(0, (sum, s) => sum + s.length * 2);
      } else if (sample is int) {
        contentSize = testData.length * 8;
      }
    }
    
    return baseSize + contentSize;
  }
}

/// 基准测试结果
class BenchmarkResult {
  final String setType;
  int insertTime = 0;
  int lookupTime = 0;
  int removeTime = 0;
  int memoryUsage = 0;
  
  BenchmarkResult(this.setType);
  
  void printResults() {
    print('=== $setType 性能基准测试结果 ===');
    print('插入时间: ${insertTime}μs');
    print('查找时间: ${lookupTime}μs');
    print('删除时间: ${removeTime}μs');
    print('内存使用: ${memoryUsage} bytes');
    print('总体评分: ${_calculateScore()}');
    print();
  }
  
  double _calculateScore() {
    // 简化的评分算法(数值越小越好)
    double timeScore = (insertTime + lookupTime + removeTime) / 3.0;
    double memoryScore = memoryUsage.toDouble();
    return (timeScore + memoryScore / 1000) / 2;
  }
}

/// 运行多种Set实现的对比测试
void runSetBenchmarkSuite() {
  List<int> testData = List.generate(50000, (i) => i);
  
  List<SetBenchmark<int>> benchmarks = [
    SetBenchmark('HashSet', () => <int>{}, testData),
    SetBenchmark('LinkedHashSet', () => LinkedHashSet<int>(), testData),
    SetBenchmark('SplayTreeSet', () => SplayTreeSet<int>(), testData),
  ];
  
  print('开始Set性能基准测试...\n');
  
  for (SetBenchmark<int> benchmark in benchmarks) {
    BenchmarkResult result = benchmark.runBenchmark();
    result.printResults();
  }
}
4. 性能回归测试
/// 性能回归测试工具
class PerformanceRegressionTester {
  final Map<String, BenchmarkResult> _baselineResults = {};
  
  /// 设置基准性能数据
  void setBaseline(String testName, BenchmarkResult result) {
    _baselineResults[testName] = result;
  }
  
  /// 运行回归测试
  void runRegressionTest(String testName, BenchmarkResult currentResult) {
    BenchmarkResult? baseline = _baselineResults[testName];
    if (baseline == null) {
      print('警告: 没有找到 $testName 的基准数据');
      return;
    }
    
    print('=== $testName 性能回归测试 ===');
    
    double insertChange = _calculatePercentageChange(
      baseline.insertTime, currentResult.insertTime);
    double lookupChange = _calculatePercentageChange(
      baseline.lookupTime, currentResult.lookupTime);
    double removeChange = _calculatePercentageChange(
      baseline.removeTime, currentResult.removeTime);
    double memoryChange = _calculatePercentageChange(
      baseline.memoryUsage, currentResult.memoryUsage);
    
    print('插入性能变化: ${insertChange.toStringAsFixed(1)}%');
    print('查找性能变化: ${lookupChange.toStringAsFixed(1)}%');
    print('删除性能变化: ${removeChange.toStringAsFixed(1)}%');
    print('内存使用变化: ${memoryChange.toStringAsFixed(1)}%');
    
    // 检查是否有显著的性能退化
    if (insertChange > 10 || lookupChange > 10 || 
        removeChange > 10 || memoryChange > 10) {
      print('⚠️  检测到显著的性能退化!');
    } else if (insertChange < -10 || lookupChange < -10 || 
               removeChange < -10 || memoryChange < -10) {
      print('✅ 检测到性能改进!');
    } else {
      print('✅ 性能保持稳定');
    }
    print();
  }
  
  double _calculatePercentageChange(int baseline, int current) {
    if (baseline == 0) return 0;
    return ((current - baseline) / baseline) * 100;
  }
}
5. 实时性能监控
/// 实时性能监控器
class RealTimeSetMonitor<T> {
  final Set<T> _set;
  final String _name;
  int _operationCount = 0;
  int _totalTime = 0;
  final Stopwatch _stopwatch = Stopwatch();
  
  RealTimeSetMonitor(this._set, this._name);
  
  bool add(T value) {
    _startOperation();
    bool result = _set.add(value);
    _endOperation('add');
    return result;
  }
  
  bool remove(T value) {
    _startOperation();
    bool result = _set.remove(value);
    _endOperation('remove');
    return result;
  }
  
  bool contains(T value) {
    _startOperation();
    bool result = _set.contains(value);
    _endOperation('contains');
    return result;
  }
  
  void _startOperation() {
    _stopwatch.reset();
    _stopwatch.start();
  }
  
  void _endOperation(String operation) {
    _stopwatch.stop();
    _operationCount++;
    _totalTime += _stopwatch.elapsedMicroseconds;
    
    // 每1000次操作输出一次统计
    if (_operationCount % 1000 == 0) {
      _printStats();
    }
  }
  
  void _printStats() {
    double avgTime = _totalTime / _operationCount;
    print('[$_name] 操作统计: 总计${_operationCount}次, '
          '平均耗时${avgTime.toStringAsFixed(2)}μs, '
          '当前大小${_set.length}');
  }
  
  /// 获取详细的性能报告
  PerformanceReport getReport() {
    return PerformanceReport(
      setName: _name,
      operationCount: _operationCount,
      totalTime: _totalTime,
      currentSize: _set.length,
      averageTime: _totalTime / _operationCount,
    );
  }
}

/// 性能报告类
class PerformanceReport {
  final String setName;
  final int operationCount;
  final int totalTime;
  final int currentSize;
  final double averageTime;
  
  PerformanceReport({
    required this.setName,
    required this.operationCount,
    required this.totalTime,
    required this.currentSize,
    required this.averageTime,
  });
  
  void printDetailedReport() {
    print('=== $setName 详细性能报告 ===');
    print('总操作次数: $operationCount');
    print('总耗时: ${totalTime}μs');
    print('平均操作时间: ${averageTime.toStringAsFixed(2)}μs');
    print('当前Set大小: $currentSize');
    print('操作效率: ${(operationCount / (totalTime / 1000000)).toStringAsFixed(0)} ops/sec');
    
    // 性能等级评估
    String performanceGrade = _getPerformanceGrade();
    print('性能等级: $performanceGrade');
  }
  
  String _getPerformanceGrade() {
    if (averageTime < 1) return 'A+ (优秀)';
    if (averageTime < 5) return 'A (良好)';
    if (averageTime < 10) return 'B (一般)';
    if (averageTime < 50) return 'C (较差)';
    return 'D (需要优化)';
  }
}
6. 性能问题诊断工具
/// 性能问题诊断工具
class SetPerformanceDiagnostic<T> {
  /// 诊断Set性能问题
  static DiagnosticReport<T> diagnose<T>(Set<T> set, List<T> sampleData) {
    DiagnosticReport<T> report = DiagnosticReport<T>(set);
    
    // 检查Set类型
    report.setType = set.runtimeType.toString();
    
    // 检查大小
    report.currentSize = set.length;
    
    // 测试插入性能
    report.insertPerformance = _testInsertPerformance(set, sampleData.take(100).toList());
    
    // 测试查找性能
    report.lookupPerformance = _testLookupPerformance(set, sampleData.take(100).toList());
    
    // 检查哈希分布(如果是HashSet)
    if (set is Set<T> && T == String) {
      report.hashDistribution = _analyzeHashDistribution(set.cast<String>());
    }
    
    // 生成建议
    report.recommendations = _generateRecommendations(report);
    
    return report;
  }
  
  static double _testInsertPerformance<T>(Set<T> set, List<T> testData) {
    Set<T> testSet = set.runtimeType == HashSet ? <T>{} : 
                     set.runtimeType.toString().contains('LinkedHashSet') ? LinkedHashSet<T>() :
                     SplayTreeSet<T>();
    
    Stopwatch sw = Stopwatch()..start();
    for (T item in testData) {
      testSet.add(item);
    }
    sw.stop();
    
    return sw.elapsedMicroseconds / testData.length;
  }
  
  static double _testLookupPerformance<T>(Set<T> set, List<T> testData) {
    Stopwatch sw = Stopwatch()..start();
    for (T item in testData) {
      set.contains(item);
    }
    sw.stop();
    
    return sw.elapsedMicroseconds / testData.length;
  }
  
  static double _analyzeHashDistribution(Set<String> stringSet) {
    if (stringSet.isEmpty) return 1.0;
    
    Map<int, int> hashBuckets = {};
    for (String item in stringSet) {
      int bucket = item.hashCode % 1000; // 简化的桶分析
      hashBuckets[bucket] = (hashBuckets[bucket] ?? 0) + 1;
    }
    
    // 计算分布均匀度(标准差)
    double mean = stringSet.length / hashBuckets.length;
    double variance = hashBuckets.values
        .map((count) => (count - mean) * (count - mean))
        .reduce((a, b) => a + b) / hashBuckets.length;
    
    return variance / mean; // 变异系数
  }
  
  static List<String> _generateRecommendations<T>(DiagnosticReport<T> report) {
    List<String> recommendations = [];
    
    // 基于Set类型的建议
    if (report.setType.contains('SplayTree') && report.currentSize > 10000) {
      recommendations.add('考虑使用HashSet以获得更好的查找性能');
    }
    
    if (report.setType.contains('LinkedHashSet') && report.currentSize > 50000) {
      recommendations.add('如果不需要保持插入顺序,考虑使用HashSet');
    }
    
    // 基于性能的建议
    if (report.insertPerformance > 10) {
      recommendations.add('插入性能较差,检查哈希函数实现或考虑批量操作');
    }
    
    if (report.lookupPerformance > 5) {
      recommendations.add('查找性能较差,可能存在哈希冲突问题');
    }
    
    // 基于哈希分布的建议
    if (report.hashDistribution != null && report.hashDistribution! > 2.0) {
      recommendations.add('哈希分布不均匀,建议优化hashCode实现');
    }
    
    if (report.currentSize > 100000) {
      recommendations.add('大型Set建议实施内存管理策略,如定期清理或分页处理');
    }
    
    if (recommendations.isEmpty) {
      recommendations.add('当前Set性能良好,无需特别优化');
    }
    
    return recommendations;
  }
}

/// 诊断报告类
class DiagnosticReport<T> {
  final Set<T> targetSet;
  String setType = '';
  int currentSize = 0;
  double insertPerformance = 0;
  double lookupPerformance = 0;
  double? hashDistribution;
  List<String> recommendations = [];
  
  DiagnosticReport(this.targetSet);
  
  void printReport() {
    print('=== Set性能诊断报告 ===');
    print('Set类型: $setType');
    print('当前大小: $currentSize');
    print('插入性能: ${insertPerformance.toStringAsFixed(2)}μs/op');
    print('查找性能: ${lookupPerformance.toStringAsFixed(2)}μs/op');
    
    if (hashDistribution != null) {
      print('哈希分布均匀度: ${hashDistribution!.toStringAsFixed(2)} (越小越好)');
    }
    
    print('\n优化建议:');
    for (int i = 0; i < recommendations.length; i++) {
      print('${i + 1}. ${recommendations[i]}');
    }
    print();
  }
}
使用性能分析工具的完整示例
/// 完整的性能分析示例
void performanceAnalysisExample() {
  print('=== Set性能分析完整示例 ===\n');
  
  // 1. 基准测试
  print('1. 运行基准测试...');
  runSetBenchmarkSuite();
  
  // 2. 内存监控
  print('2. 内存使用监控...');
  Set<String> testSet = <String>{};
  MemoryMonitor.monitorSetMemory(testSet, 'TestStringSet');
  
  // 3. 实时监控
  print('3. 实时性能监控...');
  RealTimeSetMonitor<int> monitor = RealTimeSetMonitor(<int>{}, 'RealTimeTest');
  
  for (int i = 0; i < 5000; i++) {
    monitor.add(i);
    if (i % 2 == 0) monitor.contains(i ~/ 2);
    if (i % 3 == 0) monitor.remove(i ~/ 3);
  }
  
  PerformanceReport report = monitor.getReport();
  report.printDetailedReport();
  
  // 4. 性能诊断
  print('4. 性能问题诊断...');
  Set<String> diagnosisSet = {'test1', 'test2', 'test3'};
  List<String> sampleData = List.generate(1000, (i) => 'item_$i');
  
  DiagnosticReport<String> diagnosticReport = 
      SetPerformanceDiagnostic.diagnose(diagnosisSet, sampleData);
  diagnosticReport.printReport();
  
  print('性能分析完成!');
}

通过这些性能分析和调试工具,开发者可以:

  1. 识别性能瓶颈:通过基准测试找出最慢的操作
  2. 监控内存使用:防止内存泄漏和过度消耗
  3. 实时性能跟踪:在开发过程中持续监控性能
  4. 性能回归检测:确保代码修改不会导致性能退化
  5. 问题诊断:自动分析性能问题并提供优化建议

常见陷阱和错误

1. 空大括号陷阱

// ❌ 这创建的是Map,不是Set!
var wrong = {}; // Map<dynamic, dynamic>
print(wrong.runtimeType); // _Map<dynamic, dynamic>

// ✅ 正确的空Set创建方式
var correctSet = <String>{};
var anotherSet = Set<String>();
print(correctSet.runtimeType); // _Set<String>

2. 修改不可变Set

Set<int> immutableSet = Set.unmodifiable([1, 2, 3]);

// ❌ 试图修改不可变Set
try {
  immutableSet.add(4);        // UnsupportedError
  immutableSet.remove(1);     // UnsupportedError
  immutableSet.clear();       // UnsupportedError
} catch (e) {
  print('不可变Set错误: $e');
}

// ✅ 检查Set是否可修改
extension SetExtensions<T> on Set<T> {
  bool get isModifiable {
    try {
      add(first);
      remove(first);
      return true;
    } catch (e) {
      return false;
    }
  }
}

3. 自定义对象的哈希问题

class BadPerson {
  String name;
  int age;
  BadPerson(this.name, this.age);
  
  // ❌ 只重写了==,没有重写hashCode
  @override
  bool operator ==(Object other) =>
      other is BadPerson && other.name == name;
  
  @override
  String toString() => 'BadPerson($name, $age)';
}

class GoodPerson {
  String name;
  int age;
  GoodPerson(this.name, this.age);
  
  // ✅ 同时重写==和hashCode
  @override
  bool operator ==(Object other) =>
      other is GoodPerson && other.name == name;
  
  @override
  int get hashCode => name.hashCode;
  
  @override
  String toString() => 'GoodPerson($name, $age)';
}

// 测试
Set<BadPerson> badSet = {BadPerson('Alice', 25), BadPerson('Alice', 30)};
Set<GoodPerson> goodSet = {GoodPerson('Alice', 25), GoodPerson('Alice', 30)};

print('Bad set length: ${badSet.length}'); // 可能是2(错误)
print('Good set length: ${goodSet.length}'); // 1(正确)

4. 集合运算的类型问题

Set<int> integers = {1, 2, 3};
Set<double> doubles = {2.0, 3.0, 4.0};

// ❌ 类型不匹配的运算
// Set<int> result = integers.union(doubles); // 编译错误

// ✅ 正确的处理方式
Set<num> numResult = integers.cast<num>().union(doubles.cast<num>());
print(numResult); // {1, 2, 3, 2.0, 3.0, 4.0} 注意:2和2.0是不同的

// ✅ 或者转换为相同类型
Set<int> intResult = integers.union(doubles.map((d) => d.toInt()).toSet());
print(intResult); // {1, 2, 3, 4}

5. 迭代时修改Set

Set<int> numbers = {1, 2, 3, 4, 5};

// ❌ 在遍历时修改Set会抛出异常
try {
  for (int number in numbers) {
    if (number % 2 == 0) {
      numbers.remove(number); // ConcurrentModificationError!
    }
  }
} catch (e) {
  print('并发修改错误: $e');
}

// ✅ 正确的方式:使用removeWhere
numbers.removeWhere((number) => number % 2 == 0);

// ✅ 或者先收集要删除的元素
Set<int> toRemove = numbers.where((n) => n % 2 == 0).toSet();
numbers.removeAll(toRemove);

6. Set顺序的误解

Set<int> numbers = {3, 1, 4, 1, 5, 9};

// ❌ 不要依赖Set的顺序(HashSet是无序的)
// print('First: ${numbers.first}'); // 结果不确定

// ✅ 如果需要有序,使用LinkedHashSet或排序
import 'dart:collection';

LinkedHashSet<int> orderedSet = LinkedHashSet.from([3, 1, 4, 1, 5, 9]);
print('Ordered first: ${orderedSet.first}'); // 3

List<int> sortedList = numbers.toList()..sort();
print('Sorted: $sortedList'); // [1, 3, 4, 5, 9]

7. 类型转换的安全性

Set<dynamic> mixed = {1, 'hello', 2.5, null};

// ❌ 不安全的类型转换
try {
  Set<int> integers = mixed.map((e) => e as int).toSet(); // 运行时错误!
} catch (e) {
  print('类型转换错误: $e');
}

// ✅ 安全的类型过滤和转换
Set<int> safeIntegers = mixed.whereType<int>().toSet();
print(safeIntegers); // {1}

// ✅ 带默认值的转换
Set<int> withDefaults = mixed.map((e) {
  if (e is int) return e;
  if (e is String) return int.tryParse(e) ?? 0;
  if (e is double) return e.toInt();
  return 0;
}).toSet();

最佳实践

1. 选择合适的Set实现

// ✅ 根据需求选择Set类型
import 'dart:collection';

// 需要最快的查找速度
Set<String> fastLookup = <String>{};

// 需要保持插入顺序
LinkedHashSet<String> ordered = LinkedHashSet<String>();

// 需要自动排序
SplayTreeSet<String> sorted = SplayTreeSet<String>();

// 需要自定义排序
SplayTreeSet<String> customSorted = SplayTreeSet<String>(
  (a, b) => a.length.compareTo(b.length)
);

2. 正确实现自定义对象

// ✅ 自定义类的最佳实践
class Person {
  final String name;
  final int age;
  
  const Person(this.name, this.age);
  
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Person &&
      runtimeType == other.runtimeType &&
      name == other.name &&
      age == other.age;
  
  @override
  int get hashCode => Object.hash(name, age);
  
  @override
  String toString() => 'Person($name, $age)';
}

// 使用
Set<Person> people = {
  Person('Alice', 25),
  Person('Bob', 30),
  Person('Alice', 25), // 会被自动去重
};

3. 高效的集合操作

// ✅ 使用集合运算而非循环
Set<int> set1 = {1, 2, 3, 4, 5};
Set<int> set2 = {4, 5, 6, 7, 8};

// 高效的方式
Set<int> common = set1.intersection(set2);
Set<int> combined = set1.union(set2);
Set<int> unique = set1.difference(set2);

// ✅ 批量操作
Set<int> target = <int>{};
List<int> source = [1, 2, 3, 4, 5];
target.addAll(source); // 比循环add更高效

4. 安全的类型处理

// ✅ 类型安全的Set操作
Set<dynamic> mixed = {1, 'hello', 2.5, true};

// 类型过滤
Set<int> integers = mixed.whereType<int>().toSet();
Set<String> strings = mixed.whereType<String>().toSet();

// 安全转换
Set<String> allStrings = mixed.map((e) => e.toString()).toSet();

5. 内存管理

// ✅ 及时清理大型Set
class CacheManager {
  final Set<String> _cache = <String>{};
  static const int maxSize = 1000;
  
  void addToCache(String item) {
    _cache.add(item);
    
    // 限制缓存大小
    if (_cache.length > maxSize) {
      // 可以实现LRU策略或简单清理
      _cache.clear(); // 简单清理
      _cache.add(item);
    }
  }
  
  void cleanup() {
    _cache.clear();
  }
}

6. 空安全处理

// ✅ 安全的Set操作
Set<String>? nullableSet;

// 安全访问
if (nullableSet?.isNotEmpty ?? false) {
  print(nullableSet!.first);
}

// 使用null-aware操作符
int length = nullableSet?.length ?? 0;
bool hasItems = nullableSet?.isNotEmpty ?? false;

// 安全的查找
String? found = nullableSet?.lookup('target');

总结

Dart的Set类提供了强大而高效的无重复元素集合操作。在使用时应该注意:

  1. 选择合适的实现:根据需求选择HashSet、LinkedHashSet或SplayTreeSet
  2. 注意性能影响:了解各种操作的时间复杂度,选择高效的算法
  3. 保证类型安全:使用泛型确保类型安全,正确实现自定义对象的相等性
  4. 处理边界情况:检查空Set情况和异常处理
  5. 合理使用集合运算:union、intersection、difference等方法可以让代码更简洁高效
  6. 避免常见陷阱:注意空大括号语法、不可变Set限制、并发修改等问题

通过掌握这些API和最佳实践,可以更高效地使用Dart中的Set类型,编写出高质量的代码。


本文档基于Dart 3.x版本整理,如有更新请参考官方文档。