众所周知,Dart是Flutter官方指定语言。
是一种适用于万维网的开放源代码编程语言,由Google主导开发,于2011年10月公开。它的开发团队由Google Chrome浏览器V8引擎团队的领导者拉尔斯·巴克主持,目标在于成为下一代结构化Web开发语言。摘自Wiki
先抛出一段Dart代码:
// Define a function.
printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// This is where the app starts executing.
main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}
- 其中包含了:
// 注释代码 - ... () {} 方法/函数定义
- int 变量定义,内置变量类型,强类型方式定义
- print 基础代码,用于输出日志
- '' 字符串赋值
{expression} 模板数据插入
- main() 主入口函数
- var 变量定义,不限定变量类型
一个非常好用的Dart代码测试平台:
DartPad
变量/常量
Dart中也区分变量(var)和常量(const),以及final定义的只能设置一次的变量。
Dart中,万物皆为Object,在后面文章中,一定要注意这一点,把这一点刻在心里。
内置类型:
numbers
int:-2 to 2 - 1
int x = 1;
var x = 0xFFF;
var ps = int.parse('1') // var str = ps.toString()
double: IEEE 754标准
double y = 1.1;
var y = 2.3e10
var ps = double.parse('3.1415926') // var str = ps.toString() // var str = ps.toStringAsFixed(2)
Number类型的数值支持位运算(按位与/或/位移)
var res = 2 << 1; // res is 4: 0010 << 1 = 0100 = 4
var res = 2 >> 1; // res is 1: 0010 >> 1 = 0001 = 1
var res = 3 | 8; // res is 11: 0011 | 1000 = 1011 = 11
var res = 3 & 8; // res is 0: 0011 & 1000 = 0000 = 0
strings
var s1 = 'string1'; // s1 = string1
var s2 = "string2"; // s2 = string2
var s3 = '${s1.toUpperCase()} $s2'; // s3 = STRING1 string2
booleans
var str = ''; var res = str.isEmpty; // result is true
var num = 0; var res = num < 0; //result is false
var tmp; var res = tmp == null; // result is true
var div = 0 / 0; var res = div.isNaN // result is true
lists
(also known as arrays)
List可以指定声明类型,也可以不声明类型,不声明的话其中存储的数值为var
var list = [1, "1", true];
// or
List list = [1, "1", true];
// or
List<String> list = ["1", "1", "true"]; // 如果为[1, "1", true]则会编译报错
// 另一种类型声明方式
List list = <String>[]
// 当然也可以使用const来定义常量,会覆盖var的可变性
var list = const [1,2,3];
list.add(5); // 因为定义的List为const常量,所以无法赋值,运行报错
// 可以利用循环拼接array
var list2 = [0, ...?list]; // list2 = [0, 1, "1", true]
// or
var list2 = [0, for(var i in list) '%i']; // list2 = [0, "1", "1", "true"]
// 可以使用判断语句
bool flag = true;
var list = [
1,2,3,
if (flag) 4
]; // res is 1,2,3,4
sets
Set:可以认为是去重的List,List是有序的,不唯一的,而Set是无序但唯一的。
// Set
var country = {'China', 'USA', 'UK'}
// 类型声明
Set<String> country = {'China', 'USA', 'UK'}
Set country = <String>{'China', 'USA', 'UK'}
// 枚举
for(var i in country) {} // Set中,i为值
// 也可以使用forEach
country.forEach((val) {
print('$val');
});
maps
Map:字典,由key value组成的数据,个人理解,List可以简单的理解为key为自增int的一个Map,同样,Set可以认为是没有Value只有Key的Map
// Map
var country = {
1: 'China',
2: 'USA'
}
// 类型声明
Map<int, String> country = ...;
Map country = <int, String>{};
// 枚举
for(var i in country.keys) {print(country[i]);} // Map中,i为key
// 也可以使用forEach
country.forEach((key, val) {
print('$key: $val');
});
runes
(for expressing Unicode characters in a string)
Dart中的特殊符号使用Runes来表示,是UTF-32编码的字符串。
var input = new Runes('\u2665');
var input = '\u{1f44f}';
symbols
// 待续
特性
在Dart中,不存在private/public/protect的定义方式
如果需要使用私有变量,则在变量前增加_即可,如mine为公共变量,而 _mine为私有变量
var/const/final的区别:
- var为变量,其值可以在任意地方修改
- const为常量,其值在初始化后无法修改
- final为变量,其值在第一次赋值后无法修改
函数
定义
// 带返回值的方法
bool isTest() {
return _isTest;
}
// override方法
isTest() {
return true;
}
// 方法也可以简写
bool isTest() => a == b;
参数
Dart中的传参有两种形式,固定传参和字典传参
bool isSame(int a, [int b]) {return a == b;}
bool isSame({@required int a, int b = 0}) {return a == b;}
区别:
- 固定传参不可以设默认值,字典传参可以设置默认值
- 固定传参中所定义的参数为必传,如需设置非必传,可以使用[]包裹,
字典传参为选传,如需必传,则需要增加@required。
// 调用方式
// bool isSame(int a, [int b]) {return a == b;}
isSame(1, 2);
// bool isSame({@required int a, int b = 0}) {return a == b;}
isSame(b: 2, a: 1);
- 方法嵌套与JavaScript一致
异步
首先我们要清楚的一点是:
Dart是单线程模型,类似于JavaScript,不包含主线程与子线程之分
那么,Dart中如何实现异步呢?
Dart中使用了EventLoop的方式来进行异步操作
EventLoop读取EventQueue,并进行处理,直到EventQueue为空
而新增异步代码时,则添加至EventQueue中
异步操作包含用户输入,点击,Timer,文件IO,以及自己实现的异步事件。
Event和MicroTask:
这两个应该说是借鉴了JavaScript中异步的实现方案
微任务永远优先于Event执行,类似于:
setTimeout()的方法会放在宏观任务中,类似于EventQueue
而Promise这种则会放在微观任务中,类似于MicroTask
异步任务调度
Dart中的异步任务可以使用Future来插入EventQueue中
使用scheduleMicrotask函数来插入到MicrotaskQueue中
使用方法:
Future(() {
// ...do sth
}).then((res) => {
// ...do sth
}).then((res) => {
// ...do sth
}).whenComplete(() => {
// finally
});
async.scheduleMicrotask(() => {
doTask()
});
void doTask() {
// ...do sth
}
JIT/AOT
JIT(Just in time)为实时编译模式
AOT(Ahead of time)为提前编译模式
JIT一般在Debug中使用,用于实时调试与更新至最新代码,但执行效率较低。
AOT一般用于发布生产,编译为机器码,执行效率高。
内存分配与垃圾回收
Dart的垃圾收集器是分代的,由两个部分组成:新生代空间收集器、并行标记扫描收集器,还有一个重要的东西,就是调度器
- 调度器
在Flutter引擎中,为了最小化垃圾收集对应用程序和UI性能的印象,与垃圾收集器提供了hook,当引擎检测到应用程序处于空闲状态(没有与用户交互),会发出警报,为垃圾收集器提供运行其收集阶段而不影响性能的机会。并且垃圾收集器可以在这些空闲时间运行内存压缩,从而较少内存碎片来优化内存 - 新生代空间收集器
此部分类似于Java的复制算法,用于清理寿命较短的对象,例如Stateless部件,虽然是会阻塞线程,但当与调度器结合使用,几乎感知不到应用程序在运行期间的暂停,从本质上,新建的对象被分配给内存中的连续空间,在新建对象,会被分配到下一个可用空间,直到填充完分配的内存,但Dart使用的是一个凹凸的指针,所以这个过程非常快,分配新对象的空间由两部分组成,任何时候只用一半,当一半满后,活动的对象将复制到另一半空间中,一半就会全部清空,确定对象是否活动,收集器以根对象开始,进行检测他们引用的内容,这一部分类似于Java的可达性算法,有引用的对象将会被复制到另一个空间中 - 并行标记扫描收集器当对象达到一定的生命周期时,会被提上到另一个新的内存空间,由另一个收集器管理,此收集器有两个阶段:
- 遍历对象,标记仍在使用的对象
- 扫描整个存储器,并回收未标记的对象,然后清除所有标记