Dart语言
变量声明
类似于 JavaScript 中的
var
,它可以接收任何类型的变量,但最大的不同是 Dart 中 var 变量一旦赋值,类型便会确定,则不能再改变其类型
var t = "hi world";
// 下面代码在dart中会报错,因为变量t的类型已经确定为String,
// 类型一旦确定后则不能再更改其类型。
t = 1000;
dynamic
和 Object
Object
是 Dart 所有对象的根基类,也就是说在 Dart 中所有类型都是Object
的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object
声明的对象。dynamic
与Object
声明的变量都可以赋值任意对象,且后期可以改变赋值的类型,这和var
是不同的
dynamic t;
Object x;
t = "hi world";
x = 'Hello Object';
//下面代码没有问题
t = 1000;
x = 1000;
//dynamic与Object不同的是dynamic声明的对象编译器会提供所有可能的组合,而Object声明的对象只能使用 Object 的属性与方法, 否则编译器会报错,如:
dynamic a;
Object b = "";
main() {
a = "";
printLengths();
}
printLengths() {
// 正常
print(a.length);
// 报错 The getter 'length' is not defined for the class 'Object'
print(b.length);
}
final
和const
如果您从未打算更改一个变量,那么使用
final
或const
,不是var
,也不是一个类型。 一个final
变量只能被设置一次,两者区别在于:const
变量是一个编译时常量(编译时直接替换为常量值),final
变量在第一次使用时被初始化。被final
或者const
修饰的变量
//可以省略String这个类型声明
final str = "hi world";
//final String str = "hi world";
const str1 = "hi world";
//const String str1 = "hi world";
空安全(null-safety)
定义变量时我们可以指定变量是可空还是不可空;
如果一个变量我们定义为可空类型,在某些情况下即使我们给它赋值过了,但是预处理器仍然有可能识别不出,这时我们就要显式(通过在变量后面加一个”!“符号)告诉预处理器它已经不是null了
int i = 8; //默认为不可空,必须在定义时初始化。
int? j; // 定义为可空类型,对于可空变量,我们在使用前必须判空。
// 如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,
// 表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错
late int k;
k=9;
////////////////////////////////////////////////////////////////////
class Test{
int? i;
Function? fun;
say(){
if(i!=null) {
print(i! * 8); //因为已经判过空,所以能走到这 i 必不为null,如果没有显式申明,则 IDE 会报错
}
if(fun!=null){
fun!(); // 同上
}
}
}
fun?.call() // fun 不为空时则会被调用
函数
Dart是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征
函数声明
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理,注意,函数返回值没有类型推断
typedef bool CALLBACK();
//不指定返回类型,此时默认为dynamic,不是bool
isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void test(CALLBACK cb){
print(cb());
}
//报错,isNoble不是bool类型
test(isNoble);
//对于只包含一个表达式的函数,可以使用简写语法
bool isNoble (int atomicNumber)=> true ;
函数作为变量
var say = (str){
print(str);
};
say("hi world");
函数作为参数传递
//定义函数execute,它的参数类型为函数
void execute(var callback) {
callback(); //执行传入的函数
}
//调用execute,将箭头函数作为参数传递
execute(() => print("xxx"))
可选的位置参数
//包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面:
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
//下面是一个不带可选参数调用这个函数的例子:
say('Bob', 'Howdy'); //结果是: Bob says Howdy
//下面是用第三个参数调用这个函数的例子:
say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
可选的命名参数
//定义函数时,使用{param1, param2, …},放在参数列表的最后面,用于指定命名参数。例如:
void enableFlags({bool bold, bool hidden}) {
// ...
}
//调用函数时,可以使用指定命名参数。例如:paramName: value
enableFlags(bold: true, hidden: false);
mixin
Dart 是不支持多继承的,但是它支持 mixin,简单来讲 mixin 可以 “组合” 多个类,我们通过一个例子来理解。
定义一个 Person 类,实现吃饭、说话、走路和写代码功能,同时定义一个 Dog 类,实现吃饭、和走路功能:
//定义了几个 mixin,然后通过 with 关键字将它们组合成不同的类。有一点需要注意:如果多个mixin 中有同名方法,with 时,会默认使用最后面的 mixin 的,mixin 方法中可以通过 super 关键字调用之前 mixin 或类中的方法。
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{}
异步支持
Dart类库有非常多的返回
Future
或者Stream
对象的函数。 这些函数被称为异步函数:它们只会在设置好一些耗时操作之后返回,比如像 IO操作。而不是等到这个操作完成。
async
和await
关键词支持了异步编程,允许您写出和同步代码很像的异步代码。
Future
Future
与JavaScript中的Promise
非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果,要么成功,要么失败。由于本身功能较多,这里我们只介绍其常用的API及特性。还有,请记住,
Future
的所有API的返回值仍然是一个Future
对象,所以可以很方便的进行链式调用。
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
Future.wait
有些时候,我们需要等待多个异步任务都执行结束后才进行一些操作,比如我们有一个界面,需要先分别从两个网络接口获取数据,获取成功后,我们需要将两个接口数据进行特定的处理后再显示到UI界面上,应该怎么做?答案是
Future.wait
,它接受一个Future
数组参数,只有数组中所有Future
都执行成功后,才会触发then
的成功回调,只要有一个Future
执行失败,就会触发错误回调。类似js的
Promise.all
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);
});
async/await
Dart中的
async/await
和JavaScript中的async/await
功能是一样的:异步任务串行化。
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
Stream
Stream
也是用于接收异步事件数据,和Future
不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。Stream
常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。
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