Dart语言由Google公司提出
- 基于 AOT(ahead of time) 的发布包:在发布时可以通过 AOT 生成高效的机器码以保证应用性能。而 JavaScript 则不具有这个能力。
- 基于 JIT (just in time)的快速开发周期: 在开发阶段采用,采用 JIT 模式,这样就避免了每次改动都要进行编译,极大的节省了开发时间;
因此是一种开发高效、执行简单的语言。其特殊的热重载功能,在开发中能实时刷新安卓页面而不用重新打包。
数据类型
- 未初始化的数据类型都是null,包括数字和布尔类型
变量与常量
- 显示指定类型
String name = "张三";
num age = 18;
- 使用
var
,隐式定义
var address = "日落大道";
var id = 108;
3.动态改变类型的变量采用Object
或Dynamic
定义
Object var1 = '1';
var1 = 1;
Dynamic var2 = 2;
var2 = 'hello';
- 常量采用
final
或const
修饰
final
运行时常量
const
编译时常量
final time = new DateTime.now(); // 正确
const time = new DateTime.now(); // 错误
const list = const[1,2,3]; // 正确
const list = [1,2,3]; // 错误
字符串
- 单引号、双引号都可
- ''' '''或""" """可包含多行
- 字符串前加
r
可不加转义符 -
${}
可进行字符串拼接,变量可省略大括号,表达式必须带括号
// 当仅取变量值时,可以省略花括号
var aStr2 = "hello,$name"; // hello,王五
// 当拼接的是一个表达式时,则不能省略花括号
var str1 = "link";
var str2 = "click ${str1.toUpperCase()}";
print(str2); // click LINK
列表
和Java类似
var list = [1,2,3];
var list = const[1,2,3];//不可变
映射
相当于Java的HashMap
// 1.通过字面量创建Map
var gifts = {
'first' : 'partridge',
'second': 'turtledoves',
'fifth' : 'golden rings'
};
// 2.使用Map类的构造函数创建对象
var pic = new Map();
// 往Map中添加键值对
pic['first'] = 'partridge';
pic['second'] = 'turtledoves';
pic['fifth'] = 'golden rings';
函数
- 函数也是对象,类型是
function
- 可赋值给变量,也可当作其他函数的参数
- 所有函数都有返回值,不写返回null
函数类型
- 命名可选参数: 根据参数名传值
- 位置可选参数:根据参数位置传值
///命名可选参数
// 定义一个函数,参数列表用花括号包裹
enableFlags({bool bold, bool hidden}) {
// do something
}
// 调用方式,传参时使用"参数名:值"的形式
enableFlags(hidden:true, bold:false);
///位置可选函数
// 定义add函数
add(int x, [int y, int z]){
int result = x;
if (y != null){
result = result + y;
}
if (z != null){
result = result + z;
}
print(result);
}
// 调用
add(18); // 18
add(18,12); // 30
add(18, 12, 15); // 45
匿名函数
匿名函数是一个lambda表达式或闭包
与普通函数一样有参数列表,函数体,只是没有函数名
// 定义匿名函数,并将其赋值给一个变量func
//注意,函数体最后的花括号处必须有分号结束。
var func = (x,y){
return x + y;
};
箭头函数
函数体只有return语句可简写
add(num x, num y) => x+y;
//匿名箭头函数
var function = add(num x, num y) => x+y;
运算符
基本和Java
相同,包含+,-,*,/,%
,另外增加一个~/
运算符代表整除。
条件表达式
支持三目表达式condition ? expr1 : expr2
判空表达式 ??expr
//若expr1不为空返回expr1的值,若expr1为空则返回expr2
expr1 ?? expr2
级联运算符
..
连续调用类的多个方法
new Person()..setName("Bob")..setAge(20)..save();
分支与循环
条件分支
-
if
分支与Java
相同 -
switch
分支case
可使用整数、字符串、枚举类型和编译时常量
循环 - 基本循环与
Java
类似 - 特有循环
var myList = ['Java','JavaScript','Dart'];
// for...in...循环,类似Java中的增强for
for (var it in myList ){
print(it);
}
// forEach循环。其参数为一个Function对象,这里传入一个匿名函数
myList.forEach((var it){
print(it);
});
// 可以使用匿名箭头函数简写
myList.forEach((it) => print(it));
var myMap = {
'zhangsan':'201901',
'lisi':'201902',
'wangwu':'201902'
};
// forEach遍历Map
myMap.forEach((k, v) => print("$k : $v"));
// 根据键获取值来遍历。通过keys返回Map中所有键的集合
for(var k in myMap.keys){
print("$k : ${myMap[k]}");
}
mixin
Dart
不支持多继承,但支持mixin
,mixin
修饰的类可以用with
进行组合
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{}
异步支持
Future函数
//Future.then 接收异步结果
Future.delayed(Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});
//Future.catchError 捕获异步错误
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print("success");
}).catchError((e){
//执行失败会走到这里
print(e);
});
//Future.whenComplete //异步请求完成回调
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
//Future.wait //接受异步`Future`数组参数,只有所有操作执行成功才进入`then`回调,否则触发错误回调
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
回调地狱(Callback Hell
)
如果代码中有大量异步逻辑,并且出现大量异步任务依赖其它异步任务的结果时,必然会出现Future.then
回调中套回调情况。举个例子,比如现在有个需求场景是用户先登录,登录成功后会获得用户ID,然后通过用户ID,再去请求用户个人信息,获取到用户个人信息后,为了使用方便,我们需要将其缓存在本地文件系统,代码如下:
//先分别定义各个异步任务
Future login(String userName, String pwd){
...
//用户登录
};
Future getUserInfo(String id){
...
//获取用户信息
};
Future saveUserInfo(String userInfo){
...
// 保存用户信息
};
login("alice","******").then((id){
//登录成功后通过,id获取用户信息
getUserInfo(id).then((userInfo){
//获取用户信息后保存
saveUserInfo(userInfo).then((){
//保存用户信息,接下来执行其它操作
...
});
});
})
如果业务逻辑中有大量异步依赖的情况,将会出现上面这种在回调里面套回调的情况,过多的嵌套会导致的代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback Hell
)
使用Future消除Callback Hell
login("alice","******").then((id){
return getUserInfo(id);
}).then((userInfo){
return saveUserInfo(userInfo);
}).then((e){
//执行接下来的操作
}).catchError((e){
//错误处理
print(e);
});
使用 async/await 消除 callback hell
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
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: (){
});
全文参考
Dart语言基础语法
Flutter实战·第二版