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;
}
}
最佳实践
- 合理使用 Mixin 组合功能
- 避免 Mixin 之间的冲突
- 为扩展方法提供文档
- 使用有意义的命名
- 注意扩展方法的作用域
注意事项
- Mixin 不支持构造函数
- 注意 Mixin 的顺序
- 避免过度使用扩展方法
- 处理好命名冲突
- 考虑扩展方法的性能影响
总结
Mixin 和扩展是 Dart 中强大的代码复用机制,通过合理使用这些特性,可以编写出更加模块化、可维护的代码。理解并掌握这些知识对于开发高质量的 Flutter 应用至关重要。