Flutter圈子让前端飞Flutter中文社区

Flutter Dart语法学习

2020-05-10  本文已影响0人  Miaoz0070
Dart

开发FlutterApp之前我们肯定要先了解Dart这门语言及语言的特性、语法等。最近看了大量的Dart语言相关内容,本章会来简述。
目录

概念及优点:
变量
var a = "字符串";
//主意:如果这样就会报错,类型在第一次指定后就不能改变
a = 1;

原因:Dart是强类型语言,任何变量都有各自的类型,编译时会根据首次赋值数据的类型来推断其类型,编译结束后其类型不能更改。JS是纯粹的弱类型脚本语言,var只是变量的声明。

dynamic a = "字符串";
//不会报错
a = 1;
Object b = "hello world";
//不会报错
b = 10;

不同之处,dynamic声明的对象编译器会提供所有可能的组合,至少不会报错(但有可能运行时会因为找不到之前预制的组合,造成崩溃), 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错。

dynamic a = "";
Object b = "";
//编译器不报错,不警告。
print(a.length);
//编译器会警告报错(Object没有length的getter方法):The getter 'length' is not defined for the class 'Object'
print(b.length);

注意:dynamic可以理解为id类型,任何类型都可以转换成id(dynamic)类型,可以用id(dynamic)去接,编译器不会报错,但是在运行时可能会产生错误出现崩溃现象。

final a = "名字";
//会报错
a = "性别";
final aList = const[];
const bList = const[];
var cList = const[];

这里的aList和bList就是两个空的、不可变的列表集合,而cList则是空的、可变的列表集合;
需要注意的是:cList可以重新赋值,可以改变,而aList和bList不可以重新赋值;
返回类型  方法体  (参数1,  参数2, ...){
    方法体...
    return 返回值
}

String getPerson(String name, int age){
  return name + '${age}';
}

//如果返回类型不指定时,此时默认为dynamic。

2.箭头函数
对于只包含一个表达式的函数,可以使用简写语法。

getPerson(name,  age) => name+ ', $age' ; 

bool isNoble (int atomicNumber)=> _nobleGases [ atomicNumber ] != null ;

3.函数作为变量(方法对象)、入参

//函数作为变量
var  method1 = (str){
print(str)
};
method1("kakalala");

//函数作为参数
void execute(var callbackMethod){
callbackMethod();
}
//两种
execute(() => print("xxx"));
execute(method1("kakalala"));

4.可选参数(可选位置参数、可选命名参数)

getPerson(String name, [int age = 99, String gender = "御姐"]){
  print ("name = $name, age = $age, gender = $gender");
}

//getPerson() ;这种不传参是会报错的。
getPerson(null) ;
getPerson('不知火') ;
getPerson('不知火', 100);
getPerson('不知火', null,  "萝莉");

控制台输出

flutter: name = null, age = 99, gender = 御姐
flutter: name = 不知火, age = 99, gender = 御姐
flutter: name = 不知火, age = 100, gender = 御姐
flutter: name = 不知火, age = null, gender = 萝莉

注意:name参数是必须传入的,否则会报错。后边的可选位置参数如果不传会是null,传null还是会返回null。可选位置参数可以设置默认参数。

getPerson(String name, {int age = 100, String gender = "狼狗"}){
  print("name = $name, age = $age, gender = $gender");
}

//getPerson() ;这种不传参是会报错的。
getPerson(null) ;
getPerson('烬天玉藻前') ;
getPerson('烬天玉藻前', age: 99 );
getPerson('烬天玉藻前', gender: "御姐" );
getPerson('烬天玉藻前', age: 99, gender: "奶狗");

控制台输出:

flutter: name = null, age = 100, gender = 狼狗
flutter: name = 烬天玉藻前, age = 100, gender = 狼狗
flutter: name = 烬天玉藻前, age = 99, gender = 狼狗
flutter: name = 烬天玉藻前, age = 100, gender = 御姐
flutter: name = 烬天玉藻前, age = 99, gender = 奶狗

注意:固定参数必须传入(那怕传个null),可选命名参数可以设置默认参数。

注意,不能同时使用可选的位置参数和可选的命名参数
//这种是不可以的,错误事例。
getPerson(String name, {int age = 100, String gender = "狼狗"}, [int age2 = 1002, String gender2 = "狼狗2"]){
 
}
闭包

闭包是一个方法(对象),闭包定义在其它方法内部,能够访问外部方法的局部变量,并持有其状态。

void main() {

    // 创建一个函数add1,返回加2
    Function add1 = addNum(2);
    
    // 创建一个函数add2,返回加4
    Function add2 = addNum(4);

    // 2 + 3 = 5
    print(add1(3));
    // 4 + 3 = 7
    print(add2(3));
}

// 返回一个函数对象,功能是返回累加的数字
Function addNum(int addBy){
    return (int i) => addBy + I;
}

控制台输出:

flutter: 5
flutter: 7
异步支持

Dart代码运行在一个单线程,如果Dart代码阻塞了---例如,程序计算很长时间,或者等待I/O,整个程序就会冻结。
Dart异步函数:Future、Stream,设置好耗时操作后返回,不会阻塞线程。
async和await关键词支持了异步编程,允许写出和同步代码很像的异步代码。

Future

Future与JS中的Promise和Swift的RXSwift非常相似,其语法也是链式函数调用,该函数异步操作执行后,最终返回成功(执行成功的操作)、失败(捕获错误或者停止后续操作),失败和成功是对立的只会出现一种。
注意:Future 的所有API的返回值都是一个Future对象,所以可以进行链式调用。

Future(FutureOr<T> computation())
computation 的返回值可以是普通值或者是Future对象,但是都是Future对象接收。

 Future<num> future1 = Future(() {
  print('async call1');
  return 123;
});
//直接调用
future1.then((data) {
  //执行成功会走到这里
  print(data);
}, onError: (e) {
  print("onError: \$e");
}).catchError((e) {
  //执行失败会走到这里
  print(e);
}).whenComplete(() {
  //无论成功或失败都会走到这里
});

Future<Future> future2 = Future((){
    print('async call2');
    return future1;
});

//嵌套调用
future2.then((value) => value).then((value) => {
   print('222---'+value.toString())
});

控制台打印

Reloaded 1 of 499 libraries in 154ms.
flutter: async call1
flutter: 123
flutter: async call2
flutter: 222---123

注意:computation函数体中的代码是被异步执行的,与JS中Promise构造函数的回调执行时机不一样,如需要被同步执行,则使用如下这个命名构造函数:

Future.sync(FutureOr<T> computation())

//该段代码放到上边代码之后执行
Future<num> future3 = Future.sync((){
    print('sync call');
    return 333;
});

future3.then((value) => {
   print('sync'+'$value')
});

控制台输出

flutter: sync call
flutter: sync333
flutter: async call1
flutter: 123
flutter: async call2
flutter: 222---123

由此可见,future3(sync)方法会先执行,之后在执行之前的future1、future2.可见正常的future中的computation函数体中的代码是被异步执行的。

Future.delayed(new Duration(seconds: 2),(){
   return "延迟2s执行";
}).then((data){
   print(data);
});
Future.delayed(new Duration(seconds: 2),(){
   //return "延迟2s执行";
   throw AssertionError("Error");  
}).then((data){
   //执行成功会走到这里  
   print("success");
}).catchError((e){
   //执行失败会走到这里  
   print(e);
});

在异步任务中抛出了一个异常,then的回调函数将不会被执行, catchError回调函数将被调用;并不是只有 catchError回调才能捕获错误,then方法还有一个可选参数onError(之前介绍结构体时已经提到),我们也可以它来捕获异常:

Future.delayed(new Duration(seconds: 2), () {
    //return "延迟2s执行";
    throw AssertionError("Error");
}).then((data) {
    print("success");
}, onError: (e) {
    print(e);
});
Future.delayed(new Duration(seconds: 2),(){
   //return "延迟2s执行";
   throw AssertionError("Error");
}).then((data){
   //执行成功会走到这里 
   print(data);
}).catchError((e){
   //执行失败会走到这里   
   print(e);
}).whenComplete((){
   //无论成功或失败都会走到这里
});
Future<List<Future>> future4 = Future.wait([
 // 2秒后返回结果  
 Future.delayed(new Duration(seconds: 2), () {
   return "延迟2s执行";
 }),
 // 4秒后返回结果  
 Future.delayed(new Duration(seconds: 4), () {
   return " 延迟4s执行";
 })
])

future4.then((value) => {
print(value[0]+ value[1]);
}).catchError((e){
 print(e);
});

控制台输出

//等待4s输出
flutter: 延迟2s执行 延迟4s执行
//先分别定义各个异步任务
Future<String> future1(String str1){
    ...
//第一个任务
};
Future<String> future2(String str2){
    ...
//第二个任务
};
Future future3(String info){
    ...
    // 第三个任务
};

future1("str1").then((str2){
 //1返回数据,作为2的参数
 future2(str2).then((info){
    //2的返回数据,作为3的入参
    future3(info).then((){
       //获取3的返回数据
        ...
    });
  });
})

Future消除Callback Hell
使用Future的链式机制,依次向下就避免了嵌套。跟JS的Promise完全一样。不足之处是还是有一层回调。

future1("str1").then((str2){
      return future2(str2);
}).then((info){
    return future3(info);
}).then((e){
   //执行3接下来的操作 
}).catchError((e){
  //错误处理  
  print(e);
});

async/await消除callback hell
上边的方式虽然避免了嵌套,但是在每个方法还是有一层回调。我们可以使用async/await来实现像同步代码那样来执行异步任务而不使用回调的方式。

task() async {
   try{
    String str2 = await future1("str1");
    String info = await future2(str2);
    await future3(info);
    //执行接下来的操作   
   } catch(e){
    //错误处理   
    print(e);   
   }  
}

async/await只是一个语法糖,JS编译器或Dart解释器最终都会将其转化为一个JS的Promise和Dart的Future的调用链。

Stream

如果说Future是可以接收单个异步事件返回单个事件的成功失败,那么Stream就可以接收多个异步事件,并返回多个事件的成功失败,供使用者使用。
使用场景:多次读取数据的异步任务场景,如网络内容下载、文件读写等
该例子借助了其他地方的例子。

Stream.fromFutures([
  // 1秒后返回结果
  Future.delayed(new Duration(seconds: 1), () {
    return "hello 1";
  }),
  // 抛出一个异常
  Future.delayed(new Duration(seconds: 2),(){
    throw AssertionError("Error");
  }),
  // 3秒后返回结果
  Future.delayed(new Duration(seconds: 3), () {
    return "hello 3";
  })
]).listen((data){
   print(data);
}, onError: (e){
   print(e.message);
},onDone: (){

});

控制台输出

flutter: hello 1
flutter: Error
flutter: hello 3

Future.wait是函数中存在多个延时操作,则以延时最长操作完成后统一返回,其他的延时操作等待最长的延时操作完成。
async/await:处理多个异步操作,前后有依赖逻辑的,使用异步实现同步。
Stream:统一监听该Stream中的多个异步延时操作返回,相当于之前的多个Future异步处理统一监听。

到这里大概把Dart中经常使用的语法和属性方法介绍了一遍,有错误或者理解不到位的地方,可以提出,共同进步。

Dart相比Java和JavaScript还是有许多优点有优势的,Dart既能进行服务端脚本、APP开发、web开发,但是生态目前不足,不过Flutter目前火热,相信生态之后会越来越好。

上一篇下一篇

猜你喜欢

热点阅读