基本语法
扩展是 Dart 2.7 引入的特性,用来给现有的类添加新的方法、属性、操作符,而不用修改类本身,也不用继承它。
extension 扩展名 on 类型 {
// 添加方法
返回类型 方法名(参数) {
...
}
// 添加 getter
返回类型 get 名称 => ...;
// 添加 setter
set 名称(类型 值) => ...;
}
基本使用
示例:给 String 添加方法
//StringExtension 现在不仅有自带的两个方法,还包含了String里面所有的方法
// 例如:contains、startsWith、endsWith 等等
extension StringExtension on String {
/// 检查字符串是否是回文
/// 回文是指正着读和反着读都一样的字符串
/// 例如:'level'、'radar'、'madam' 等
/// 注意:此方法忽略大小写和空格
bool get isPalindrome {
// 首先去除字符串中的空格,并转换为小写
// \s+ 匹配一个或多个空格
var cleaned = replaceAll(RegExp(r'\s+'), '').toLowerCase();
// 然后检查清理后的字符串是否等于它的反转
// split('') 将字符串拆分为字符列表,reversed 反转列表,join('') 将字符列表重新组合成字符串
var reversed = cleaned.split('').reversed.join('');
return cleaned == reversed;
}
/// 将字符串的首字母大写
String capitalize() {
// isEmpty 检查字符串是否为空
// isEmpty 是一个 getter,返回 true 如果字符串长度为 0
// 谁在调用 isEmpty?是 this,也就是当前字符串实例
// 可以直接使用 this.isEmpty,或者使用 isEmpty
// 省略 this 的规则是:如果在类内部访问属性或方法,可以省略 this
// StringExtension 拓展方法中,this 指代当前字符串实例
if (isEmpty) return this;
return this[0].toUpperCase() + substring(1);
}
}
void main() {
print('level'.isPalindrome); // true
print('dart'.capitalize()); // Dart
// 还可以使用其他 String 方法
// 下面这些方法都是 String 类自带的方法
print('hello world'.contains('world')); // true
print('hello world'.startsWith('hello')); // true
print('hello world'.endsWith('world')); // true
}
on String
表示这是扩展String
类型可以添加
getter
(isPalindrome
)和普通方法(capitalize()
)
如何理解extension StringExtension on String
extension StringExtension on String {
bool get isPalindrome => this == split('').reversed.join('');
}
上面的代码表面上就像是把 isPalindrome
这个新方法“加到了” String
类型上,这样在使用的时候就能写:
print('abcba'.isPalindrome); // true
但是本质上它并没有真的去修改 String
类(Dart 核心类是不可改的)。实际上是编译器看到'abcba'.isPalindrome
时,其实会悄悄替换成:
StringExtension('abcba').isPalindrome
也就是说,这只是编译期的语法糖,它让你看起来好像 String
自带了这个方法,但底层并不是改了 String
类本身。
给泛型类型添加扩展
extension ListSum<T extends num> on List<T> {
T sum() {
//reduce: 将列表中的所有元素通过指定的函数进行累加
// (a + b) as T: 将 a 和 b 相加,并将结果转换为 T 类型
// 不转换不行么? // 需要转换为 T 类型,因为 reduce 返回的是 dynamic 类型
// 如果不转换为 T 类型,可能会导致类型不匹配的错误
// The returned type 'num' isn't returnable from a 'T' function,
// as required by the closure's context.
return reduce((a, b) => (a + b) as T);
}
}
void main() {
// [1, 2, 3].sum() : 会调用 ListSum<int> 的 sum 方法
// 会推断出 T 是 int 类型
print([1, 2, 3].sum()); // 6
print([1.5, 2.5].sum()); // 4.0
}
扩展自己的类
class Person {
String name;
Person(this.name);
}
// 给 Person 扩展新功能
extension PersonExtension on Person {
void sayHello() {
print('Hello, my name is $name');
}
String get upperName => name.toUpperCase();
}
void main() {
var p = Person('Alice');
p.sayHello(); // 调用扩展方法
print(p.upperName); // 调用扩展 getter
}
命名扩展 & 冲突解决
如果多个扩展有同名方法,Dart 会报方法冲突,此时:
- 你可以显式调用扩展名来区分:
extension ExtA on String {
String hello() => 'A: $this';
}
extension ExtB on String {
String hello() => 'B: $this';
}
void main() {
print(ExtA('dart').hello()); // A: dart
print(ExtB('dart').hello()); // B: dart
}
扩展的限制
不能添加字段(实例变量),只能添加方法、getter、setter
不能重写现有方法(不会覆盖原方法)
不是真正修改类,只是语法糖,编译时会转化成静态方法调用
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com