重学Flutter之----Dart高级语法糖回顾

944 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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
  • 使用 Future API(会有一篇文章专门讲解)

async 和 await

虽然FutureAPI就可以实现异步的操作,但是太过于复杂和代码难以阅读,我们在开发中比较多的使用asyncawait来使用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后来操作的效果,如果们使用asyncawait来实现:

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() 执行完毕后才执行,接下来的其它类似函数也如此