携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第十九天,点击查看活动详情
重学Flutter之----Dart高级语法糖回顾
泛型
在Dart中也存在泛型的概念,如果对泛型没有基本的概念可以参考这篇文章Kotlin深入浅出系列------泛型对方形有个了解。
泛型主要是有以下两点好处:
- 不需要类型转换,并且减少类型转换的隐藏错误
- 减少重复代码
不需要类型转换,并且减少类型转换的隐藏错误
我们在容器类(List、Map等)中看到泛型,如下代码所示:
var names = List<String>();
names.addAll(['张三', '李四', '王五']);
names.add(42); // 静态解析的时候就会提示错误
解析:
上面代码中声明了一个String类型的List,这样就告诉编译器这个List就只能存放String,当我们添加num类型就出在编译期间出错,减少了类型转换类型的错误。
减少重复代码
那么为什么List需要泛型呢?就是因为减少重复代码,我们来看看List中怎么使用泛型的:
abstract class List<E> implements EfficientLengthIterable<E>
首先声明一个泛型E,然后再传给EfficientLengthIterable。
我们在看一下添加和获取:
//添加
void add(E value);
//获取
E operator [](int index);
我们发现在add中没有指定固定的数据类型,也是使用泛型,在获取的时候也是返回泛型,我们在声明的时候就确定了该List的存放类型,这样就大大减少了因数据类型要写List<int>、List<String>等类。
限制泛型类型
我们在Kotlin深入浅出系列------泛型中也了解了可以限制它的类型,在Dart中也是可以限制泛型类型。我们需要使用extends关键字来限制,指定该类型必须是某个类或者该类的子类。请看下面例子:
class Person{
}
class Zhangsan extends Person{
}
class Users<E extends Person>{
void add(E user){
}
}
main() {
Users users = Users();
users.add(Person());
users.add(Zhangsan());
users.add("");//编译器报错
//定义泛型类型是Zhangsan
Users users2 = Users<Zhangsan>();
//父类也可以,Dart是面向对象的语言,父类引用指向子类对象,这就是多态效果
users2.add(Person());
users2.add(Zhangsan());
users.add("");//编译器报错
Users users3= Users<String>();//编译器直接报错,必须要是Person类型或其子类
}
Future和 async-await
在Dart中代码运行在单个执行“线程”中,如果我们进行耗时操作(长时间运行的计算操作或等待 I/O)等造成了执行堵塞,此时整个程序就会被“冻结”
我们需要异步处理来完成这些操作,那么我们就需要使用Future来表示异步操作的结果,你可以用 async 和 await 关键字或 Future 类的相关 API 来配合使用 future
future是什么
future 是 Future<T> 类的对象,T就是上面所说的泛型,表示异步操作的返回结果,如果我们需要返回结果则可以这样写Future<void>。当一个返回 future 对象的函数被调用时,会发生两件事:
- 将函数操作列入队列等待执行并返回一个未完成的
Future对象 - 不久后当函数操作执行完成,
Future对象变为完成并携带一个值或一个错误
当你写的代码依赖于 future 对象时,你有两种可选的实现方式:
- 使用关键字
async和await - 使用
FutureAPI(会有一篇文章专门讲解)
async 和 await
虽然FutureAPI就可以实现异步的操作,但是太过于复杂和代码难以阅读,我们在开发中比较多的使用async 和 await来使用Future
async函数,返回值是一个Future对象,如果没有返回Future对象,会自动将返回值包装成Future对象。 捕捉错误,一般是使用try/catch机制来做异常处理。 await 一个future,可以拿到Future的结果,直到拿到结果,才执行下一步的代码
await只能在async函数出现
我们来看一下简单的使用:
void main() {
var future = Future(() {
Future.delayed(const Duration(milliseconds: 1000), () {
print("猫");
});
});
print("狗");
}
输出:
狗
猫
我们使用了Future来完成延迟1s后来操作的效果,如果们使用async和await来实现:
void main() async {
var future = new Future.delayed(new Duration(seconds: 1), () {
return "猫";
});
var result = await future;
print(result + "狗");
}
输出:
猫狗
错误处理
如果一个 Future 在函数返回完成时有错误,你可能想要捕获该错误。异步函数中可以使用 try-catch 语句来处理错误:
void main() async {
try {
var future = new Future.delayed(new Duration(seconds: 1), () {
return throw FormatException('手动错误');;
});
var result = await future;
print(result);
} catch (e) {
print("出现错误:${e.toString()}");
}finally{
}
}
输出:
出现错误:FormatException: 手动错误
顺序处理
当我们多个耗时操作,但又需要进行一定的顺序的时候,我们可以使用多个 await 表达式来确保各个语句在执行下一个语句之前完成:
main() async {
await expensiveA();
await expensiveB();
doSomethingWith(await expensiveC());
}
解析:
函数 expensiveB() 将会在函数 expensiveA() 执行完毕后才执行,接下来的其它类似函数也如此