在这里插入图片描述

6.1 泛型 - 就像万能容器

// 泛型就像一个万能盒子,可以装任何类型的东西
class Box<T> {
  T? _content;
  
  void put(T item) {
    _content = item;
    print('放入了:$item');
  }
  
  T? get() {
    print('取出了:$_content');
    return _content;
  }
  
  bool get isEmpty => _content == null;
}

void genericExample() {
  // 装字符串的盒子
  var stringBox = Box<String>();
  stringBox.put('Hello World');
  String? message = stringBox.get();
  
  // 装数字的盒子
  var numberBox = Box<int>();
  numberBox.put(42);
  int? number = numberBox.get();
  
  // 装任何东西的盒子
  var flexibleBox = Box<dynamic>();
  flexibleBox.put('文字');
  flexibleBox.put(123);
}

// 泛型函数
T getFirst<T>(List<T> list) {
  if (list.isEmpty) {
    throw ArgumentError('列表不能为空');
  }
  return list.first;
}

void genericFunctionExample() {
  List<String> names = ['Alice', 'Bob', 'Charlie'];
  String firstName = getFirst(names);  // 自动推断类型
  
  List<int> numbers = [1, 2, 3];
  int firstNumber = getFirst<int>(numbers);  // 明确指定类型
}

6.2 扩展方法 - 就像给现有工具添加新功能

扩展方法让你可以给现有类添加新功能,而不需要修改原始代码。

🔧 基础扩展方法
// 给String类添加新功能
extension StringExtensions on String {
  // 判断是否是邮箱
  bool get isEmail {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this);
  }
  
  // 首字母大写
  String get capitalize {
    if (isEmpty) return this;
    return this[0].toUpperCase() + substring(1).toLowerCase();
  }
  
  // 反转字符串
  String get reverse {
    return split('').reversed.join('');
  }
  
  // 移除所有空格
  String get removeSpaces => replaceAll(' ', '');
  
  // 判断是否是数字
  bool get isNumeric => double.tryParse(this) != null;
  
  // 截断字符串
  String truncate(int maxLength, {String suffix = '...'}) {
    if (length <= maxLength) return this;
    return substring(0, maxLength - suffix.length) + suffix;
  }
}

// 给List添加新功能
extension ListExtensions<T> on List<T> {
  // 安全获取元素
  T? safeGet(int index) {
    if (index >= 0 && index < length) {
      return this[index];
    }
    return null;
  }
  
  // 随机获取元素
  T? get random {
    if (isEmpty) return null;
    return this[DateTime.now().millisecond % length];
  }
  
  // 分块处理
  List<List<T>> chunk(int size) {
    List<List<T>> chunks = [];
    for (int i = 0; i < length; i += size) {
      chunks.add(sublist(i, math.min(i + size, length)));
    }
    return chunks;
  }
  
  // 去重
  List<T> get unique => toSet().toList();
  
  // 计数
  Map<T, int> get frequency {
    Map<T, int> freq = {};
    for (T item in this) {
      freq[item] = (freq[item] ?? 0) + 1;
    }
    return freq;
  }
}
⚡ 高级扩展技巧
// 给数字类型添加扩展
extension NumExtensions on num {
  // 限制在范围内
  num clamp(num min, num max) => math.max(min, math.min(max, this));
  
  // 转换为百分比字符串
  String get asPercentage => '${(this * 100).toStringAsFixed(1)}%';
  
  // 判断是否在范围内
  bool between(num min, num max) => this >= min && this <= max;
  
  // 四舍五入到指定小数位
  double roundTo(int decimals) {
    double factor = math.pow(10, decimals).toDouble();
    return (this * factor).round() / factor;
  }
}

// 给DateTime添加扩展
extension DateTimeExtensions on DateTime {
  // 是否是今天
  bool get isToday {
    DateTime now = DateTime.now();
    return year == now.year && month == now.month && day == now.day;
  }
  
  // 是否是昨天
  bool get isYesterday {
    DateTime yesterday = DateTime.now().subtract(Duration(days: 1));
    return year == yesterday.year && month == yesterday.month && day == yesterday.day;
  }
  
  // 友好的时间显示
  String get timeAgo {
    Duration diff = DateTime.now().difference(this);
  
    if (diff.inDays > 0) return '${diff.inDays}天前';
    if (diff.inHours > 0) return '${diff.inHours}小时前';
    if (diff.inMinutes > 0) return '${diff.inMinutes}分钟前';
    return '刚刚';
  }
  
  // 格式化为中文日期
  String get chineseDate => '$year$month$day日';
}

// 给Map添加扩展
extension MapExtensions<K, V> on Map<K, V> {
  // 安全获取值
  V? safeGet(K key) => containsKey(key) ? this[key] : null;
  
  // 过滤Map
  Map<K, V> where(bool Function(K key, V value) test) {
    Map<K, V> result = {};
    forEach((key, value) {
      if (test(key, value)) {
        result[key] = value;
      }
    });
    return result;
  }
  
  // 转换值
  Map<K, R> mapValues<R>(R Function(V value) transform) {
    Map<K, R> result = {};
    forEach((key, value) {
      result[key] = transform(value);
    });
    return result;
  }
}

// 条件扩展 - 只对特定类型有效
extension IntExtensions on int {
  // 判断是否是偶数
  bool get isEven => this % 2 == 0;
  
  // 判断是否是奇数
  bool get isOdd => this % 2 != 0;
  
  // 生成范围
  List<int> to(int end) {
    return List.generate(end - this + 1, (i) => this + i);
  }
  
  // 重复执行
  void times(void Function(int index) action) {
    for (int i = 0; i < this; i++) {
      action(i);
    }
  }
}

// 可空类型的扩展
extension NullableStringExtensions on String? {
  // 是否为空或null
  bool get isNullOrEmpty => this == null || this!.isEmpty;
  
  // 获取非空值或默认值
  String orDefault(String defaultValue) => this ?? defaultValue;
  
  // 安全调用
  String? ifNotEmpty(String Function(String) action) {
    if (this != null && this!.isNotEmpty) {
      return action(this!);
    }
    return null;
  }
}
🎯 实际应用示例
void extensionExample() {
  // String扩展使用
  String email = 'user@example.com';
  print('是邮箱吗?${email.isEmail}');  // true
  
  String name = 'john doe';
  print('首字母大写:${name.capitalize}');  // John doe
  
  String text = 'hello world';
  print('反转:${text.reverse}');  // dlrow olleh
  print('移除空格:${text.removeSpaces}');  // helloworld
  print('截断:${text.truncate(8)}');  // hello...
  
  // List扩展使用
  List<String> fruits = ['苹果', '香蕉', '橙子', '苹果'];
  print('安全获取:${fruits.safeGet(10)}');  // null
  print('随机水果:${fruits.random}');
  print('去重:${fruits.unique}');  // [苹果, 香蕉, 橙子]
  print('分块:${fruits.chunk(2)}');  // [[苹果, 香蕉], [橙子, 苹果]]
  
  // 数字扩展使用
  double score = 0.856;
  print('百分比:${score.asPercentage}');  // 85.6%
  print('四舍五入:${score.roundTo(2)}');  // 0.86
  
  int number = 42;
  print('是偶数:${number.isEven}');  // true
  print('范围:${3.to(7)}');  // [3, 4, 5, 6, 7]
  
  // 重复执行
  3.times((i) => print('第${i + 1}次'));
  
  // DateTime扩展使用
  DateTime now = DateTime.now();
  print('是今天:${now.isToday}');  // true
  print('中文日期:${now.chineseDate}');
  
  DateTime past = now.subtract(Duration(hours: 2));
  print('时间差:${past.timeAgo}');  // 2小时前
  
  // 可空字符串扩展
  String? nullableText;
  print('是否为空:${nullableText.isNullOrEmpty}');  // true
  print('默认值:${nullableText.orDefault('默认文本')}');  // 默认文本
}

如果文章对您有帮助,麻烦动动发财的小手点赞、关注和收藏,您的反馈将是作者不断更新的动力🙏🏻

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐