本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、扩展的基本语法
1.1 基本定义
extension <ExtensionName> on <Type> {
// 方法、getter、setter、操作符等
}
1.2 示例:为 String 添加新功能
extension StringEnhancements on String {
// 添加一个反转字符串的方法
String get reversed {
return split('').reversed.join();
}
// 添加判断是否为有效邮箱方法
bool get isValidEmail {
final regex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
return regex.hasMatch(this);
}
}
void main() {
String text = 'hello';
print(text.reversed); // 输出: olleh
String email = 'user@example.com';
print(email.isValidEmail); // 输出: true
}
二、扩展的不同类型
2.1 实例方法扩展
extension NumberFormatters on int {
// 将数字格式化为带千位分隔符的字符串
String formatWithCommas() {
final numberStr = toString();
final result = StringBuffer();
for (int i = 0; i < numberStr.length; i++) {
if (i > 0 && (numberStr.length - i) % 3 == 0) {
result.write(',');
}
result.write(numberStr[i]);
}
return result.toString();
}
}
void main() {
int price = 1234567;
print(price.formatWithCommas()); // 输出: 1,234,567
}
2.2 Getter 扩展
extension DateTimeHelpers on DateTime {
// 判断日期是否为今天
bool get isToday {
final now = DateTime.now();
return year == now.year && month == now.month && day == now.day;
}
// 获取该日期的开始时间(00:00:00)
DateTime get startOfDay {
return DateTime(year, month, day);
}
}
void main() {
DateTime today = DateTime.now();
DateTime tomorrow = today.add(const Duration(days: 1));
print(today.isToday); // 输出: true
print(tomorrow.isToday); // 输出: false
print(today.startOfDay); // 输出: 2024-01-15 00:00:00.000
}
2.3 操作符扩展
extension ListOperations<T> on List<T> {
// 自定义操作符:列表相乘(重复n次)
List<T> operator *(int times) {
if (times <= 0) return [];
final result = <T>[];
for (int i = 0; i < times; i++) {
result.addAll(this);
}
return result;
}
}
void main() {
List<int> numbers = [1, 2, 3];
List<int> repeated = numbers * 3;
print(repeated); // 输出: [1, 2, 3, 1, 2, 3, 1, 2, 3]
}
三、泛型扩展
extension CollectionUtils<T> on List<T> {
// 安全地获取元素,索引越界时返回null
T? getSafe(int index) {
if (index >= 0 && index < length) {
return this[index];
}
return null;
}
// 将列表分成指定大小的块
List<List<T>> chunk(int size) {
if (size <= 0) return [];
final chunks = <List<T>>[];
for (int i = 0; i < length; i += size) {
final end = (i + size) < length ? (i + size) : length;
chunks.add(sublist(i, end));
}
return chunks;
}
}
void main() {
List<String> fruits = ['apple', 'banana', 'orange', 'grape', 'mango'];
print(fruits.getSafe(10)); // 输出: null
print(fruits.getSafe(2)); // 输出: orange
List<List<String>> chunks = fruits.chunk(2);
print(chunks); // 输出: [[apple, banana], [orange, grape], [mango]]
}
四、扩展的命名和冲突解决
4.1 命名扩展
// 为同一类型创建多个扩展时使用命名
extension StringValidators on String {
bool get isStrongPassword {
return length >= 8 &&
contains(RegExp(r'[A-Z]')) &&
contains(RegExp(r'[0-9]'));
}
}
extension StringFormatters on String {
String get capitalizeFirst {
if (isEmpty) return this;
return this[0].toUpperCase() + substring(1).toLowerCase();
}
}
void main() {
String password = 'Password123';
print(password.isStrongPassword); // 输出: true
String name = 'dart language';
print(name.capitalizeFirst); // 输出: Dart language
}
4.2 处理扩展冲突
当多个扩展有相同名称的成员时,可以使用显式语法:
extension TextUtils on String {
String truncate(int maxLength) {
if (length <= maxLength) return this;
return '${substring(0, maxLength)}...';
}
}
extension StringManipulation on String {
String truncate(int maxLength, {String suffix = '***'}) {
if (length <= maxLength) return this;
return '${substring(0, maxLength)}$suffix';
}
}
void main() {
String longText = '这是一个很长的文本需要截断显示';
// 使用显式语法解决冲突
print(TextUtils(longText).truncate(5)); // 输出: 这是一个很...
print(StringManipulation(longText).truncate(5, suffix: '>>>')); // 输出: 这是一个很>>>
}
五、扩展的限制
-
不能添加实例变量
-
不能访问类的私有成员
-
不能覆盖已有的方法
-
扩展方法是静态解析的(在编译时确定)
-
扩展名是可选的,但推荐使用以提高可读性
813

被折叠的 条评论
为什么被折叠?



