一、语言特性
- 基本类型:bool,int,double。没有 byte、char 和 float
- final和java中一样,赋值不可再改变。const 表示一个编译时常量,在程序编译的时候它的值就确定了
- Dart 里所有的东西都是对象,包括 int、函数、null,所有对象继承制Object
- Dart 是动态类型语言, 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的),未初始化的变量的初始值为null(包括数字)
- Dart 提供了顶级函数(如:main())
- Dart 没有 public、private、protected 关键字,变量名以"_"开头意味着对它的 lib 是私有的
- Dart 中的类和接口是统一的,类即接口,类/接口可以继承也可以实现。同时支持基于mixin的继承方式,一定程度上可以多重继承。
二、组成
编程语言并不是孤立存在的,Dart也是这样,他由语言规范、虚拟机、类库和工具等组成:
- SDK:SDK 包含 Dart VM、dart2js、Pub、库和工具。
- Dartium:内嵌 Dart VM 的 Chromium ,可以在浏览器中直接执行 dart 代码。
- Dart2js:将 Dart 代码编译为 JavaScript 的工具。
- Dart Editor:基于 Eclipse 的全功能 IDE,并包含以上所有工具。支持代码补全、代码导航、快速修正、重构、调试等功能。
三、语法(与java差异)
1、检测两个 String 的内容是否一样事,我们使用 == 进行比较;如果要测试两个对象是否是同一个对象(indentity test),使用 identical 函数
2、Dart 提供了 for-in 循环,forEach循环
var list = ['apples', 'bananas', 'oranges'];
for (var e in list) {
print(e);
}
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
如果函数只包含一条语句,可以使用箭头符号=>来缩短它
list.forEach((item) => print('${list.indexOf(item)}: $item'));
3、类型判断关键字(顺带转换) is,类型的强制转换关键字 as
dynamic obj = <String, int>{};
if (obj is Map<String, int>) {
// 进过类型判断后,Dart 知道 obj 是一个 Map,所以不用再强制转换 obj 的类型
obj['foo'] = 42;
}
// 虽然as可以进行类型的强制转换,但为了更安全的转换,更推荐使用 is
var map = obj as Map<String, int>
4、可以使用单引号或双引号来创建一个字符串。嵌套时,可以单引号嵌套双引号,或者双引号嵌套单引号。使用表达式时需要${表达式}
String hello= 'hello world';
String words = '"what he said" - ${hello}';
print(words);
//输出 "what he said" - hello world
5、在Dart中,数组是List对象,可以直接打印,在java中需遍历。
//创建一个int类型的list
List list = [10, 7, 23];
// 输出[10, 7, 23]
print(list);
// 使用List的构造函数,也可以添加int参数,表示List固定长度,不能进行添加 删除操作
var fruits = new List();
// 添加元素
fruits.add('apples');
// 添加多个元素
fruits.addAll(['oranges', 'bananas']);
List subFruits = ['apples', 'oranges', 'banans'];
// 添加多个元素
fruits.addAll(subFruits);
// 输出: [apples, oranges, bananas, apples, oranges, banans]
print(fruits);
// 获取List的长度
print(fruits.length);
// 获取第一个元素
print(fruits.first);
// 获取元素最后一个元素
print(fruits.last);
// 利用索引获取元素
print(fruits[0]);
// 查找某个元素的索引号
print(fruits.indexOf('apples'));
// 删除指定位置的元素,返回删除的元素
print(fruits.removeAt(0));
// 删除指定元素,成功返回true,失败返回false
// 如果集合里面有多个“apples”, 只会删除集合中第一个改元素
fruits.remove('apples');
// 删除最后一个元素,返回删除的元素
fruits.removeLast();
// 删除指定范围(索引)元素,含头不含尾
fruits.removeRange(start,end);
// 删除指定条件的元素(这里是元素长度大于6)
fruits.removeWhere((item) => item.length >6);
// 删除所有的元素
fruits.clear();
6、Map
//声明方式一:
Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度'};
//声明方式二:
Map companys = new Map();
companys['Alibaba'] = '阿里巴巴';
// 指定键值对的参数类型
var aMap = new Map<int, String>();
// Map的赋值,中括号中是Key,这里可不是数组
aMap[1] = '小米';
//map里面value可以为空字符串,也可以为null
aMap[2] = '';
// 检索Map是否含有某Key
assert(aMap.containsKey(1));
//删除某个键值对
aMap.remove(1);
7、函数
Dart 中支持可选参数、也可以默认参数。如果是
void main() {
print(foo(2));
print(foo(1, 2));
}
int foo(int x, [int y]) {
// 是的,int 也可以是 null
if (y != null) {
return x + y;
}
return x;
}
//默认参数也是支持的
int foo(int x, [int y = 0]) {
return x + y;
}
可以使用具名参数,具名参数是必须的时候,使用注解 @required
void main() {
print(foo(x: 1, y: 2));
// 具名参数的顺序可以是任意的
print(foo(y: 3, x: 4));
// 所有的具名参数都是可选的,这个调用是合法的,但它会导致 foo() 在运行时抛异常
print(foo());
}
int foo({ @required int x, int y}) {
return x + y;
}
Dart 不支持函数的重载。
8、Dart 可以抛出任意类型的对象,甚至可以通过 rethrow 再抛出异常
throw Exception('here is an error message');
throw 'Out of Control!';
try {
} on FormatException catch (e) { // 捕获特定类型的异常
} on Exception { // 捕获特定类型的异常,但不需要这个对象
} catch (e) { // 捕获所有异常
} finally {
}
void test() {
try {
print('1');
} catch (e) {
print('2');
rethrow;// 如果不重新抛出异常,main函数中的catch语句执行不到
}
}
void main() {
try {
test();
} catch (e) {
print('3');
}
}
9、级联符号 .. 允许在同一个对象上进行一系列操作
querySelector('#confirm')
..text = 'Confirm'
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
//上面的写法相当于下面,需要注意的是级联的前提是返回值部委void
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
10、使用new语句来构造一个类,构造函数的名字可能是ClassName,也可以是ClassName.identifier
var jsonData = JSON.decode('{"x":1, "y":2}');
// Create a Point using Point().
var p1 = new Point(2, 2);
// Create a Point using Point.fromJson().
var p2 = new Point.fromJson(jsonData);
11、使用 ?.
来确认前操作数不为空, 常用来替代.
, 避免左边操作数为null引发异常
// If p is non-null, set its y value to 4.
p?.y = 4;
12、类的初始化
//方式一
class point {
int x;
int y;
point(this.x, this.y);
}
//方式二:初始化列表(initializer list)的方式
class Point {
int x;
int y;
// 由于是在 initializer list 中,Dart 知道第一个 x 是 this.x,
// 第二个 x 是构造函数的参数
Point(int x, int y) : x = x, y = y {
// ...
}
}
13、继承
class Point2D {
int x;
int y;
Point2D(this.x, this.y);
}
class Point3D extends Point2D {
int z;
// 父类的构造函数只能在 initializer list 里调用
Point3D(int x, int y, int z): z = z, super(x, y) {
}
}
注意一下初始化顺序:
- 先执行子类 initializer list,但只初始化自己的成员变量
- 初始化父类的成员变量
- 执行父类构造函数的函数体
- 执行之类构造函数的函数体
基于这个初始化顺序,推荐是把 super() 放在 initializer list 的最后。此外,在 initializer list 里不能访问 this(也就是说,只能调用静态方法)
使用 mixins 多继承,在 with 关键字后面跟一个或多个 mixin 的名字。
class dove extends Birds with Animal {
// ...
}
mixins的多重继承是一定程度的,被mixin的类不声明任何构造函数,不调用 super
abstract class Animal{
bool canFly = false;
bool canCry = false;
void entertainMe() {
if (canFly ) {
} else if (canCry ) {
} else {
}
}
}
14、异步和线程
Dart 是单线程的,主线程由一个事件循环来执行(类似 Android 的主线程)。对于异步代码,我们通过 Future 来获取结果
void foo1() {
var file = File('path-to-your-file');
file.exists()
.then((exists) => print('file ${exists ? 'exists' : 'not exists'}'))
.catchError((e) => print(e));
print('bar: after file.exists() returned');
}
Dart 2 提供了 async 函数,用来简化这种编程范式。下面这段代码的效果跟上面是一样的,但有区别:foo1 函数里面,file.exists() 执行完后,会马上执行下面的语句;而 foo2 则会等待结果,然后才继续执行。
void foo2() async {
var file = File('path-to-your-file');
try {
var exists = await file.exists();
print('file ${exists ? 'exists' : 'not exists'}');
print('bar: after file.exists() returned');
} catch (e) {
print(e);
}
}
感谢: