Dart SDK 中鲜为人知的类和函数
· 阅读需 14 分钟
最近,Flutter 社区 itsallwidgets 建了一个论坛,目前加入的人不多,大家可以注册账号,跟国 外的活跃开发者们一起讨论关于 Flutter 开发的话题。
虽然人不多,但也有一些比较有意思的主题讨论,其中一个主题是: Lesser known classes and functions from the Dart core libraries ,讨论一些日常开发中比较少用到,但是却很有意思和实用的类和函数。
本文分成两部分,第一部分是对论坛评论里提到的类和函数进行总结,第二部分将额外补充一些没有提到的。
第一部分:论坛评论
1. package:collection
中的minBy()
和maxBy()
函数
- 功能:用于从可迭代对象中找到满足特定条件的最小值或最大值的元素,相比对整个可迭代对象进行排序后取最值,效率更高。
- 示例代码:
import 'package:collection/collection.dart';
void main() {
final numbers = [5, 3, 8, 1, 9];
final minNumber = numbers.minBy((num) => num);
final maxNumber = numbers.maxBy((num) => num);
print('最小值: $minNumber');
print('最大值: $maxNumber');
}
2. Iterable<T>
的nonNulls
扩展
- 功能:用于从可迭代对象中过滤出非空值,使代码更简洁,避免使用
SizedBox.shrink()
等占位符。 - 示例代码:
void main() {
final listWithNulls = [1, null, 3, null, 5];
final nonNullList = listWithNulls.nonNulls;
print(nonNullList);
}
3. package:async
的AsyncCache.ephemeral
- 功能:确保回调函数最多同时执行一次,适用于防止按钮多次点击重复执行异步操作等场景。
- 示例代码:
import 'package:async/async.dart';
Future<void> asyncOperation() async {
await Future<void>.delayed(const Duration(seconds: 2));
print('Executed');
}
void main() {
final AsyncCache _cache = AsyncCache.ephemeral();
ElevatedButton(
onPressed: () => _cache.fetch(asyncOperation),
child: const Text('Execute'),
);
}
在上述代码中,多次点击按钮时,asyncOperation
函数只会执行一次,直到其完成。
4. firstWhereOrNull
- 功能:在可迭代对象中查找满足条件的第一个元素,如果未找到则返回
null
,相比firstWhere
在未找到元素时抛出异常更安全。 - 示例代码:
class MyStuff {
final String id;
MyStuff(this.id);
}
void main() {
final someStuffs = [MyStuff('Dog'), MyStuff('Cat'), MyStuff('Bird')];
MyStuff? stuff = someStuffs.firstWhereOrNull((element) => element.id == 'Cat');
print(stuff);
}
5. 解码 HTTP 响应的优化方式
- 功能:在解码 HTTP 响应时,不在主隔离区将长字符串解析为
Map
,而是在新隔离区中使用Utf8Decoder
与JsonDecoder
融合的方式,提高性能。 - 示例代码:
import 'dart:convert';
import 'dart:isolate';
import 'package:http/http.dart' as http;
Future<Map<String, dynamic>?> isolateHttpResponseDecoder(
http.Response httpResponse,
) async =>
Isolate.run(
() => const Utf8Decoder().fuse(const JsonDecoder()).convert(httpResponse.bodyBytes) as Map<String, dynamic>?,
);
void main() async {
final response = await http.get(Uri.parse('https://example.com/api/data'));
final decodedData = await isolateHttpResponseDecoder(response);
print(decodedData);
}
6. FutureRecord2
扩展
- 功能:用于更方便、易读 地并行等待多个
Future
,相比Future.wait()
或[...].wait
,它能正确推断返回值类型。 - 示例代码:
Future<String> fetchText() async {
await Future.delayed(Duration(seconds: 1));
return 'Hello';
}
Future<String> fetchImage() async {
await Future.delayed(Duration(seconds: 2));
return 'Image data';
}
void main() async {
var (text, image) = await (fetchText(), fetchImage()).wait;
print('Text: $text');
print('Image: $image');
}
7. Completer<T>
- 功能:用于手动控制
Future
的完成状态,当需要在特定条件下完成Future
时非常有用。 - 示例代码:
import 'dart:async';
void main() {
final completer = Completer<String>();
// 模拟一个异步操作,在2秒后完成Future并传递数据
Future.delayed(Duration(seconds: 2), () {
completer.complete('Data from async operation');
});
// 等待Future完成并获取结果
completer.future.then((value) {
print(value);
});
}
8. unawaited
函数
-
功能描述:
unawaited
是dart:async
提供的一个实用函数,用于标记一个异步操作可以被安全忽略。这通常在不关心 Future 结果时使用,比如在触发后台操作但不想阻塞当前任务时。它有助于明确表明故意忽略异步任务的意图,避免潜在的代码警告。 -
示例代码:
import 'dart:async';
void main() {
// 模拟一个异步后台任务
Future<void> performBackgroundTask() async {
await Future.delayed(Duration(seconds: 1));
print('后台任务完成');
}
// 使用 unawaited 表明无需等待任务完成
unawaited(performBackgroundTask());
// 继续执行其他逻辑
print('主线程继续执行');
}
-
注意事项:
unawaited
不会停止异步任务,它只是告诉工具和开发者该任务可以被忽略。- 使用时确保任务失败不会影响应用的其他部分。
- 需要导入
dart:async
。
-
常见用途:
- 启动后台任务。
- 在不阻塞主逻辑的情况下触发不重要的异步操作,比如日志记录或缓存更新。
提示
unawaited
跟不使用unawaited
和await
函数没有本质区别,unawaited
在语义上会更明确一些。
// 使用 unawaited 表明无需等待任务完成
unawaited(performBackgroundTask());
// 不使用 unawaited,也不用 await ,效果一样
performBackgroundTask();
第二部分:额外补充
搜集一些网络上和自己日常开发中遇到的类和函数。
List.generate
函数
- 功能描述:
- 用于生成一个具有指定长度的列表,并且 可以通过一个回调函数来初始化列表中的每个元素。这在需要创建一个有规律的列表时非常有用,比如创建一个包含从 1 到 n 的整数列表,或者一个包含 n 个相同初始值的列表等。
- 示例代码:
- 创建一个包含 10 个整数(从 0 到 9)的列表:
void main() {
List<int> numbers = List.generate(10, (index) => index);
print(numbers);
}
- 创建一个包含 5 个字符串(每个字符串都是"Hello")的列表:
void main() {
List<String> greetings = List.generate(5, (index) => "Hello");
print(greetings);
}
StringBuffer
类和相关函数
- 功能描述:
StringBuffer
用于高效地构建字符串。在需要拼接多个字符串时,直接使用+
操作符可能会导致创建多个中间字符串对象,效率较低。而StringBuffer
可以在一个对象中逐步添加字符串片段,最后通过toString
方法获取拼接好的完整字符串,性能更好。- 示例代码:
- 拼接一个包含多个单词的句子:
void main() {
StringBuffer buffer = StringBuffer();
buffer.write("Hello");
buffer.write(" ");
buffer.write("World");
String sentence = buffer.toString();
print(sentence);
}