第一章 起步#
弹射起步
变量声明#
- var 声明变量,但是类型后面不可以改变了,根据第一次赋值数据的类型来推断其类型,编译结束后其类型就已经被确定
- dynamic 和 Object 声明动态变量,后面类型也可以改变,不同点在于dynamic可以调用可以用的属性(有运行时风险),Object 只能调用Object提供的属性
- final const final是运行时常量,const是编译时常量,同时用final或者const修饰的变量可以不加类型
- 空类型 安全
1
2
3
4
5
6
7
|
int i = 8; //默认为不可空,必须在定义时初始化。
int? j; // 定义为可空类型,对于可空变量,我们在使用前必须判空。
// 如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,
// 表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错
late int k;
k=9;
|
- 函数式编程
- Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理,返回值没有类型推断
- 支持箭头函数,只有一个语句的函数,使用箭头函数简写
- 函数做为变量
1
2
3
4
|
var say = (str){
print(str);
};
say("hi world");
|
1
2
3
4
|
void execute(var callback) {
callback();
}
execute(() => print("xxx"))
|
- 可选的位置参数 包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面:
1
2
3
4
5
6
7
|
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
|
- 可选的命名参数 定义函数时,使用{param1, param2, …},放在参数列表的最后面,用于指定命名参数。例如:
1
2
3
4
|
//设置[bold]和[hidden]标志
void enableFlags({bool bold, bool hidden}) {
// ...
}
|
- mixin Dart 是不支持多继承的,但是它支持 mixin,简单来讲 mixin 可以 “组合” 多个类,我们通过一个例子来理解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class Person {
say() {
print('say');
}
}
mixin Eat {
eat() {
print('eat');
}
}
mixin Walk {
walk() {
print('walk');
}
}
mixin Code {
code() {
print('key');
}
}
class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}
|
ps:
- 不能同时使用位置参数和命名参数
- 我们定义了几个 mixin,然后通过 with 关键字将它们组合成不同的类。有一点需要注意:如果多个mixin 中有同名方法,with 时,会默认使用最后面的 mixin 的,mixin 方法中可以通过 super 关键字调用之前 mixin 或类中的方法。
异步支持#
Future#
Future.then#
为了方便示例,在本例中我们使用Future.delayed 创建了一个延时任务(实际场景会是一个真正的耗时任务,比如一次网络请求),即2秒后返回结果字符串"hi world!",然后我们在then中接收异步结果并打印结果,代码如下:
1
2
3
4
5
|
Future.delayed(Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});
|
Future.catchError#
1
2
3
4
5
6
7
8
9
10
|
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print("success");
}).catchError((e){
//执行失败会走到这里
print(e);
});
|
或者使用then的onError可选参数
1
2
3
4
5
6
7
8
|
Future.delayed(Duration(seconds: 2), () {
//return "hi world!";
throw AssertionError("Error");
}).then((data) {
print("success");
}, onError: (e) {
print(e);
});
|
Future.whenComplete#
无论成功失败都走的块
1
2
3
4
5
6
7
8
9
10
11
12
|
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
|
Future.wait#
类似于GCD group
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Future.wait([
// 2秒后返回结果
Future.delayed(Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});
|
执行上面代码,4秒后你会在控制台中看到“hello world”。
里面的两个任务都执行完成后才会走到then
async/await#
避免回调低于,用同步的写法写出异步的代码
回调地狱
1
2
3
4
5
6
7
8
9
10
|
login("alice","******").then((id){
//登录成功后通过,id获取用户信息
getUserInfo(id).then((userInfo){
//获取用户信息后保存
saveUserInfo(userInfo).then((){
//保存用户信息,接下来执行其他操作
...
});
});
})
|
1
2
3
4
5
6
7
8
9
10
|
login("alice","******").then((id){
return getUserInfo(id);
}).then((userInfo){
return saveUserInfo(userInfo);
}).then((e){
//执行接下来的操作
}).catchError((e){
//错误处理
print(e);
});
|
Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用” ,如果在then 中返回的是一个Future的话,该future会执行,执行结束后会触发后面的then回调,这样依次向下,就避免了层层嵌套。
- 使用 async/await 消除callback hell
1
2
3
4
5
6
7
8
9
10
|
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
|
- async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用 then 方法添加回调函数。
- await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。
其实,无论是在 JavaScript 还是 Dart 中,async/await 都只是一个语法糖,
译器或解释器最终都会将其转化为一个 Promise(Future)的调用链。
Stream#
Stream 也是用于接收异步事件数据,和 Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
|
输出如下:
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3