公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

Dart Mixin 和扩展详解 ​

Mixin 基础 ​

Mixin 声明 ​

dart
mixin Logger {
  void log(String message) {
    print('Log: $message');
  }
  
  void error(String message) {
    print('Error: $message');
  }
}

mixin TimeStamp {
  String getTimestamp() {
    return DateTime.now().toIso8601String();
  }
}

Mixin 使用 ​

dart
class Service with Logger, TimeStamp {
  void doSomething() {
    log('Operation started at ${getTimestamp()}');
    // 执行操作
    log('Operation completed');
  }
}

Mixin 约束 ​

on 关键字 ​

dart
// 限制只能在特定类型上使用
mixin CanFly on Bird {
  void fly() {
    print('Flying high!');
  }
}

class Bird {
  void chirp() {
    print('Chirp chirp!');
  }
}

class Eagle extends Bird with CanFly {
  // 可以使用 fly 方法
}

class Dog with CanFly {  // 错误: Dog 不是 Bird 的子类
  // 编译错误
}

多个 Mixin ​

dart
mixin A {
  String getMessage() => 'A';
}

mixin B {
  String getMessage() => 'B';
}

class C with A, B {
  // 使用最后一个 mixin 的实现
  // getMessage() 返回 'B'
}

扩展方法 ​

基本语法 ​

dart
extension StringExtension on String {
  bool isValidEmail() {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this);
  }
  
  String capitalize() {
    if (isEmpty) return this;
    return '${this[0].toUpperCase()}${substring(1)}';
  }
}

// 使用扩展方法
void main() {
  print('test@example.com'.isValidEmail()); // true
  print('hello'.capitalize()); // Hello
}

泛型扩展 ​

dart
extension ListExtension<T> on List<T> {
  T? firstWhereOrNull(bool Function(T) test) {
    for (var element in this) {
      if (test(element)) return element;
    }
    return null;
  }
  
  List<T> sortedBy(Comparable Function(T) keyExtractor) {
    var copy = [...this];
    copy.sort((a, b) => keyExtractor(a).compareTo(keyExtractor(b)));
    return copy;
  }
}

完整示例 ​

dart
// 基础日志 mixin
mixin BaseLogger {
  void log(String message) {
    print('${DateTime.now()}: $message');
  }
}

// 文件操作 mixin
mixin FileOperations {
  Future<void> writeToFile(String path, String content) async {
    log('Writing to file: $path'); // 可以使用 BaseLogger 的方法
    // 文件写入逻辑
  }
  
  Future<String> readFromFile(String path) async {
    log('Reading from file: $path');
    // 文件读取逻辑
    return 'File content';
  }
}

// 数据验证 mixin
mixin DataValidator {
  bool validateEmail(String email) {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
  }
  
  bool validatePhone(String phone) {
    return RegExp(r'^\+?[\d\s-]{10,}$').hasMatch(phone);
  }
}

// 使用多个 mixin
class UserService with BaseLogger, FileOperations, DataValidator {
  Future<void> saveUser(Map<String, String> userData) async {
    // 验证数据
    if (!validateEmail(userData['email']!)) {
      log('Invalid email address');
      return;
    }
    
    if (!validatePhone(userData['phone']!)) {
      log('Invalid phone number');
      return;
    }
    
    // 保存数据
    await writeToFile('users.json', userData.toString());
    log('User data saved successfully');
  }
}

// 扩展方法示例
extension MapExtension<K, V> on Map<K, V> {
  Map<K, V> merge(Map<K, V> other) {
    return {...this, ...other};
  }
  
  V? getPath(List<K> path) {
    var current = this;
    for (var i = 0; i < path.length - 1; i++) {
      if (current[path[i]] is! Map) return null;
      current = current[path[i]] as Map<K, V>;
    }
    return current[path.last];
  }
}

void main() async {
  // 使用 UserService
  final userService = UserService();
  await userService.saveUser({
    'email': 'test@example.com',
    'phone': '+1234567890',
  });
  
  // 使用扩展方法
  final map1 = {'a': 1, 'b': 2};
  final map2 = {'c': 3, 'd': 4};
  final merged = map1.merge(map2);
  print(merged); // {a: 1, b: 2, c: 3, d: 4}
  
  final nested = {
    'user': {
      'address': {
        'city': 'New York'
      }
    }
  };
  print(nested.getPath(['user', 'address', 'city'])); // New York
}

高级用法 ​

条件 Mixin ​

dart
mixin DebugLogger on Object {
  void debugLog(String message) {
    assert(() {
      print('Debug: $message');
      return true;
    }());
  }
}

扩展运算符 ​

dart
extension IterableExtension<T> on Iterable<T> {
  T? get firstOrNull => isEmpty ? null : first;
  
  Map<K, List<T>> groupBy<K>(K Function(T) keyExtractor) {
    var result = <K, List<T>>{};
    for (var element in this) {
      var key = keyExtractor(element);
      (result[key] ??= []).add(element);
    }
    return result;
  }
}

最佳实践 ​

  1. 合理使用 Mixin 组合功能
  2. 避免 Mixin 之间的冲突
  3. 为扩展方法提供文档
  4. 使用有意义的命名
  5. 注意扩展方法的作用域

注意事项 ​

  1. Mixin 不支持构造函数
  2. 注意 Mixin 的顺序
  3. 避免过度使用扩展方法
  4. 处理好命名冲突
  5. 考虑扩展方法的性能影响

总结 ​

Mixin 和扩展是 Dart 中强大的代码复用机制,通过合理使用这些特性,可以编写出更加模块化、可维护的代码。理解并掌握这些知识对于开发高质量的 Flutter 应用至关重要。