目录
1. 泛型 generics
1.1 泛型使用
main(List<String> args) {
var l = <String>[];
l.add('aaa');
l.add('bbb');
l.add('ccc');
print(l);
var m = <int, String>{};
m[1] = 'aaaa';
m[2] = 'bbbb';
m[3] = 'cccc';
print(m);
}
[aaa, bbb, ccc]
{1: aaaa, 2: bbbb, 3: cccc}
容器对象,在创建对象时都可以定义泛型类型
1.2 泛型函数
K addCache<K, V>(K key, V val) {
print('$key -> $val');
return val;
}
main(List<String> args) {
var key = addCache('url', 'https://wiki.doucafecat.tech');
print(key);
}
url -> https://wiki.doucafecat.tech
https://wiki.doucafecat.tech
1.3 构造函数泛型
class Phone<T> {
final T mobileNumber;
Phone(this.mobileNumber);
}
main(List<String> args) {
var p = Phone<String>('ducafecat');
print(p.mobileNumber);
}
ducafecat
这是大多数情况下使用泛型的场景,在一个类的构造函数中(Phone是一个泛型类)
(就是cpp的template)
1.4 泛型限制
定义
class AndroidPhone {
void startup() {
print('Android Phone 开机');
}
}
class Phone<T extends AndroidPhone> {
final T mobile;
Phone(this.mobile);
}
实例
main(List<String> args) {
var ad = AndroidPhone();
var p = Phone<AndroidPhone>(ad);
p.mobile.startup();
}
Android Phone 开机
通过 extends 关键字 可以限定你可以泛型使用的类型
通过 class Phone<T extends AndroidPhone> {
就可以让传入的实参必须是 AndroidPhone类型 或者 是 AndroidPhone类型的子类
2. 异步 async
2.1 异步回调 then
import 'package:dio/dio.dart';
void main() {
Dio dio = Dio();
dio.get("https://wpapi.ducafecat.tech/products/categories").then((response) {
print(response.data);
});
}
[{id: 34, name: Bag, slug: bag, parent: 0, description: ...
then
的方式异步回调
在 Dart 中,then
方法用于处理返回了 Future
的异步操作。当 Future
完成时,then
方法所传入的回调函数会被执行
2.2 异步等待 await
import 'package:dio/dio.dart';
void main() async {
Dio dio = Dio();
Response<String> response =
await dio.get("https://wpapi.ducafecat.tech/products/categories");
print(response.data);
}
[{id: 34, name: Bag, slug: bag, parent: 0, description: ...
async
写在函数定义 await
写在异步请求头
在 Dart 中,async
和 await
关键字用于简化异步编程,使得代码逻辑和控制流更像是同步代码。 它们主要用于处理 Future
对象,从而让异步代码更加易读
async
关键字:- 当你在函数声明时使用
async
关键字时,表示这个函数是异步函数 async
函数总是返回一个Future
,即使你直接返回一个非Future
类型的值(这种情况下这个值将会被自动包装成一个Future
)
- 当你在函数声明时使用
await
关键字:await
关键字只能在async
函数中使用,它用于等待一个返回Future
的表达式完成,并获取其结果- 在
await
关键字之后的代码会暂停执行,直到Future
完成,并将其结果赋值给左侧的变量
Response<String> response =
await dio.get("https://wpapi.ducafecat.tech/products/categories");
在这里,await
暂停了 main
函数的执行,直到 dio.get
异步操作完成,并将请求成功返回的响应赋值给 response
变量
2.3 异步返回值
import 'package:dio/dio.dart';
Future<String?> getUrl(String url) async {
Dio dio = Dio();
Response<String> response = await dio.get(url);
return response.data;
}
void main() async {
var content =
await getUrl('https://wpapi.ducafecat.tech/products/categories');
print(content);
}
[{id: 34, name: Bag, slug: bag, parent: 0, description: ...
定义 Future<T>
返回对象
代码展示了如何使用 Dart 中的 async
和 await
关键字来处理异步 HTTP 请求,并把请求操作提取到一个单独的函数里。这种方式不仅使代码更具有模块化,还能提高可读性和维护性
3. 生成器 generate (了解)
3.1 同步生成器 sync*
Iterable<int> naturalsTo(int n) sync* {
print('start');
int k = 0;
while (k < n) {
yield k++;
}
print('end');
}
main(List<String> args) {
var it = naturalsTo(5).iterator;
while (it.moveNext()) {
print(it.current);
}
}
start
0
1
2
3
4
end
yield 会等待 moveNext
指令
使用 sync*
的场景
延迟计算: 生成器可以在需要时生成元素,而不是一次性生成所有元素
内存效率: 适用于处理大量或无限数据流,因为它们逐个生成元素,而不需要一次性加载到内存中
流控制: 可以在生成元素之间执行其他逻辑,如打印日志、计算等
总结
sync*
关键字用于定义一个同步生成器函数,yield
则用于逐个生成元素。生成器函数非常适合处理需要延迟计算、大量数据或无限数据流的场景。它们提高了内存效率,同时保持代码简洁和易读
3.2 异步生成器 async*
import 'dart:async';
Stream<int> asynchronousNaturalsTo(int n) async* {
print('start');
int k = 0;
while (k < n) {
yield k++;
}
print('end');
}
main(List<String> args) {
// 流监听
// asynchronousNaturalsTo(5).listen((onData) {
// print(onData);
// });
// 流监听 StreamSubscription 对象
StreamSubscription subscription = asynchronousNaturalsTo(5).listen(null);
subscription.onData((value) {
print(value);
// subscription.pause();
});
}
start
0
1
2
3
4
end
以流的方式一次性推送
StreamSubscription
对象进行流监听控制
使用 StreamSubscription
的优势
流控制: StreamSubscription
对象允许你控制流的行为,比如暂停 (pause
) 和恢复 (resume
) 流
取消订阅: 你可以通过 subscription.cancel()
方法取消订阅流,避免资源浪费
监听错误和完成: 可以使用 subscription.onError
和 subscription.onDone
方法分别处理错误和流完成事件
3.3 递归生成器 sync*
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
main(List<String> args) {
var it = naturalsDownFrom(5).iterator;
while (it.moveNext()) {
print(it.current);
}
}
5
4
3
2
1
yield*
以指针的方式传递递归对象,而不是整个同步对象
4. 类型定义 typedef
4.1 typedef 定义使用
采用 typedef
typedef MyPrint = void Function(String val);
class PrintClass {
MyPrint print;
PrintClass(this.print);
}
main() {
PrintClass coll = PrintClass((String val) => print(val));
coll.print('hello world');
}
hello world
未采用 typedef
class PrintClass {
void Function(String val) print;
PrintClass(this.print);
}
main() {
PrintClass coll = PrintClass((String val) => print(val));
coll.print('hello world');
}
hello world
4.2 简化常用类型定义
定义
typedef MapStringAny = Map<String, dynamic>;
typedef MapAnyString = Map<dynamic, String>;
typedef MapStringString = Map<String, String>;
typedef MapStringDouble = Map<String, double>;
typedef MapDoubleString = Map<double, String>;
typedef MapDoubleDouble = Map<double, double>;
typedef MapIntInt = Map<int, int>;
typedef MapIntDouble = Map<int, double>;
typedef ListString = List<String>;
typedef ListInt = List<int>;
typedef ListDouble = List<double>;
typedef ListAny = List<dynamic>;
使用
main() {
ListString p = [];
p.add('a');
p.add('b');
p.add('c');
MapStringAny m = {};
m['a'] = 1;
m['b'] = 2;
m['c'] = 3;
}
5. 空安全
5.1 默认不可空
String title = 'ducafecat';
5.2 type? 可空
String? title = null;
5.3 value! 值保证不为空,主观上
String? title = 'ducafecat';
String newTitle = title!;
就是骗一骗编译器
5.4 value?. 不为空才执行
String? title = 'ducafecat';
bool isEmpty = title?.isEmpty();
5.5 value?? 如果空执行
String? title = 'ducafecat';
String newTitle = title ?? 'cat';
像构里面就挺好用的
5.6 late 声明
延迟加载修饰符
声明一个不可空的变量,并在声明后初始化
late String description;
void main() {
description = 'Feijoada!';
print(description);
}
本来要在声明的时候初始化的,加上 late 就告诉编译器我们后面再初始化
5.7 late 类成员延迟初始
class WPHttpService extends GetxService {
late final Dio _dio;
@override
void onInit() {
...
_dio = Dio(options);
...
}
加上 late
后就可以不用构造函数的时候初始化了
5.8 List、泛型
List<String?>? l;
l = [];
l.add(null);
l.add('a');
print(l);
5.9 Map
Map<String, String?>? m;
m = {};
m['a'] = 'b';
m['b'] = null;
print(m);
*
可能返回空
6. 扩展 extension
extension 本质上还是和继承一样扩展了方法
但这是一种简洁优雅的方式,你可以想想之前继承的繁琐
6.1 示例 扩展日期时间
加入依赖包 pubspec.yaml
dependencies:
intl: ^0.17.0
编写扩展类 ExDateTime
import 'package:intl/intl.dart';
extension ExDateTime on DateTime {
/// 方法,格式化日期 yyyy-MM-dd
String toDateString({String format = 'yyyy-MM-dd'}) =>
DateFormat(format).format(this);
// 属性
int get nowTicket => this.microsecondsSinceEpoch;
}
main() {
var now = DateTime.now();
print(now.toDateString());
print(now.nowTicket);
}
我们给可以扩展类加个前缀 Ex
这样一看就知道是扩展
6.2 业务场景
功能函数
视图组件
创作不易,希望读者三连支持
赠人玫瑰,手有余香
文章评论