相关概念
- 所有能够使用变量引用的都是对象, 每个对象都是一个类的实例。在 Dart 中 甚至连数字、方法和 null 都是对象。所有的对象都继承于 Object 类
- 使用静态类型( String, int, bool, num) 可以更清晰的表明你的意图,并且可以让静态分析工具来分析你的代码, 但这并不是强制性的。(在调试代码的时候你可能注意到 没有指定类型的变量的类型为 dynamic。)
- Dart 在运行之前会先解析你的代码。你可以通过使用 类型或者编译时常量来帮助 Dart 去捕获异常以及 让代码运行的更高效
- Dart 支持顶级方法 (例如 main()),同时还支持在类中定义函数。 (静态函数和实例函数)。 你还可以在方法中定义方法 (嵌套方法或者局部方法)。
- 同样,Dart 还支持顶级变量,以及 在类中定义变量(静态变量和实例变量)。 实例变量有时候被称之为域(Fields)或者属性(Properties)。
- 和 Java 不同的是,Dart 没有 public、 protected、 和 private 关键字。如果一个标识符以 (_) 开头,则该标识符 在库内是私有的
变量(variables)
变量赋值
1 | var name = 'chao'; //上面名字为 name 的变量引用了 一个内容为 “chao” 的 String 对象 |
默认值
1 | //没有初始化的变量自动获取一个默认值为 null。 |
可选的类型
在声明变量的时候,你可以选择加上具体 类型:1
String name = 'chao';
final and const
如果你以后不打算修改一个变量,使用 final 或者 const。 一个 final 变量只能赋值一次;一个 const 变量是编译时常量。 (const 变量同时也是 final 变量。) 顶级的 final 变量或者类中的 final 变量在 第一次使用的时候初始化。
const 只能被设一次值,在声明处赋值,且值必须为编译时常量;用于修饰常量。
1
2
3
4
5
6const bar = 1000000; // 定义常量值
// bar =13; // 出现异常,const修饰的变量不能调用setter方法,即:不能设值,只能在声明处设值
const atm = 1.01325 * bar; // 值的表达式中的变量必须是编译时常量(bar);
var c = 12;
// atm = 1 * c; //出错,因为c不是一个编译时常量,即:非const修饰的变量(只有const修饰的变量才是编译时常量)final:只能被设一次值,在声明处赋值,值和普通变量的设值一样,可以是对象、字符串、数字等,用于修饰值的表达式不变的变量;
- 对象成员值能被修改,对于能够添加成员的类(如List、Map)则可以添加或删除成员。(类似js中const)
- 变量本身实例不能被修改。(类似js中const)
注意: 实例变量可以为 final 但是不能是 const 。
1
2 //const就不能用在表达实例对象上
final wordPair = new WordPair.random();
内置的类型(Built-in types)
类型
number
- 分为:int、double
- strings和numbers转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
string
可以在字符串中使用表达式,用法是这样的: ${expression}。如果表达式是一个比赛服,可以省略 {}。 如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串。
1
2
3
4
5
6
7
8var s = 'string interpolation';
assert('Dart has $s, which is very handy.' ==
'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');可以使用 + 操作符来把多个字符串链接为一个,也可以把多个 字符串放到一起来实现同样的功能:
1
2
3
4
5
6
7var s1 = 'String ' 'concatenation'
" works even over line breaks.";
assert(s1 == 'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator '
+ 'works, as well.';
assert(s2 == 'The + operator works, as well.');使用三个单引号或者双引号也可以 创建多行字符串对象:
1
2
3
4
5
6var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
boolean
- 当 Dart 需要一个布尔值的时候,只有 true 对象才被认为是 true。 所有其他的值都是 false。这点和 JavaScript 不一样, 像 1、 “aString”、 以及 someObject 等值都被认为是 false。
list (也被称之为 array)
也许 array (或者有序集合)是所有编程语言中最常见的集合类型。 在 Dart 中数组就是 List 对象。所以 通常我们都称之为 lists。
1
2
3
4
5var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);在 list 字面量之前添加 const 关键字,可以 定义一个不变的 list 对象(编译时常量):
1
2var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error.
map
通常来说,Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次。
1
2
3
4
5
6
7
8
9var gifts = {
'first' : 'partridge',
'second': 'turtledoves',
'fifth' : 'golden rings'
};
var gifts = new Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';同样使用 const 可以创建一个 编译时常量的 map:
1
2
3
4
5
6final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // Uncommenting this causes an error.
rune (用于在字符串中表示 Unicode 字符)
symbol
Function
介绍
- Dart 是一个真正的面向对象语言,方法也是对象并且具有一种 类型, Function。 这意味着,方法可以赋值给变量,也可以当做其他方法的参数。 也可以把 Dart 类的实例当做方法来调用。
1
2
3
4
5
6
7
8bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//可以选择忽略类型定义
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
可选参数、默认参数、命名参数
- 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/**
* 方法的可选参数 []
* 方法的形参默认值 sex = '男'
*/
String say(String from = 'china', String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
/**
* 定义一个命名参数的方法
*/
String printUserInfoByObject(String username, {int age = 10, String sex = '女'}){
if(sex == '女'){
return '我是非常可爱,姓名:$username --- 性别:$sex --- 年龄:$age';
}
return '我是非常帅气,姓名:$username --- 性别:$sex --- 年龄:$age';
}
print(printUserInfoByObject('超超', age: 10, sex: '男'));
main() 入口函数
1 | void main() { |
静态作用域(scope)
1 | var topLevel = true; |
自执行方法、箭头函数
1 | /** |
闭包(closures)
一个 闭包 是一个方法对象,不管该对象在何处被调用, 该对象都可以访问其作用域内 的变量1
2
3
4
5
6
7
8
9
10
11
12
13/**
闭包的特点:
1. 常驻内存
2. 内部变量,不污染全局
*/
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
var add2 = makeAdder(2);
add2(2); // 4
add2(2); // 6
}
返回值
所有的函数都返回一个值。如果没有指定返回值,则 默认把语句 return null; 作为函数的最后一个语句执行。
操作符
算术操作符
1 | var a, b; |
级联操作符(..)
级联操作符 (..) 可以在同一个对象上连续调用多个函数以及访问成员变量。 使用级联操作符可以避免创建 临时变量, 并且写出来的代码看起来 更加流畅:
正确使用:1
2
3
4
5
6
7
8
9
10querySelector('#button') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
//上面代码和下面一样效果
var button = querySelector('#button');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
错误使用:1
2
3var sb = new StringBuffer();
sb.write('foo')..write('bar');
//sb.write() 函数返回一个 void, 无法在 void 上使用级联操作符。
异常(Exceptions)
异常类型
- Error
- Exception
异常调用
Throw
1
2throw new FormatException('Expected');
throw 'Expected'; //任意对象Catch
捕获异常可以避免异常继续传递(你重新抛出rethrow异常除外)1
2
3
4
5
6
7try{
}on Exception catch (e){ //指定exception类型错误
}catch(e){ //如果捕获语句没有指定类型,则可以捕获任意类型
}rethrow
把捕获的异常给重新抛出。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17final foo = '';
void misbehave() {
try {
foo = "You can't change a final variable's value.";
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}Finally
要确保某些代码执行,不管有没有出现异常都需要执行,可以使用 一个 finally 语句来实现。如果没有 catch 语句来捕获异常, 则在执行完 finally 语句后, 异常被抛出了:1
2
3
4
5
6
7try {
breedMoreLlamas();
} catch(e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}
Class
介绍
Dart 是一个面向对象编程语言,同时支持基于 mixin 的继承机制。 每个对象都是一个类的实例,所有的类都继承于 Object.。 基于 Mixin 的继承 意味着每个类(Object 除外) 都只有一个超类,一个类的代码可以在其他 多个类继承中重复使用
基本语法
A: 含义: 定义一个和类名字一样的方法就定义了一个构造函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55// dart中类的基本使用
class Person{
//公共属性
String name = 'chao';
int age = 10;
//私有属性
String _sex = '男';
//默认构造方法
//初始化属性
Person(String name, int age):name='超',age=10{
this.name = name;
this.age = age;
}
//默认构造方法简写
//Person(this.name, this.age);
//命名构造函数
Person.eat(){
print('我是命名构造函数');
}
//公共方法
String say(){
return '我叫${this.name}, 我今年${this.age}';
}
//私有方法
void _cry(){
print('我是私有方法')
}
get myName{
return this.name;
}
set myAge(int age){
this.age = age;
}
//私有方法
void _think(){
print('我是私有方法, ${this.name}正在思考中....');
}
}
Person a = new Person('chao', 20);
print(a.myName);
a.myAge = 300;
print(a.say());
print(a.age);
继承
1 | class Person { |
特点
?. 来替代 .
1 | //?. 来替代 . 可以避免当左边对象为 null 时候 抛出异常 |
级联操作..
1 | var p = new Point(2, 2); |
is 类型判断
as 类型转换
抽象类、接口
定义
- 抽象类主要是定义标准,子类可以继承抽象类,也可以实现抽象类接口。
- 抽象类通过abstract关键字来定义,定义没有方法体的方法我们称为抽象方法
- 抽象类不能被实例化,只有继承它的子类可以
- 如果子类继承抽象类必须得实现里面的抽象方法
- 子类可以实现多个接口(class C implements A,B{})
使用
extends和implements区别
- 如果要复用抽象类里面可见的方法和属性,并且要用抽象方法约束自类的话我们就用extends继承抽象类
- 如果只是把抽象类当做标准的话我们就用implements实现抽象类
代码实现
1 | // Db.dart |
mixins
介绍
用途
- 可以实现类似extends的功能,但是不是继承
- 可以mixins多个类
使用条件
- 作为mixins的类只能继承自Object,不能继承其他类
- 作为mixins的类不能有构造函数
- mixins的实例类型就是超类的子类型
- with为mixins的关键字
使用
1 |
|
泛型
泛型作用
在Dart中类型是可选的,你可以选择不用泛型,使用泛型有下面几个好处:
- 有些情况下你可能想使用类型来表明你的意图,不管是使用泛型还是具体类型。
- 可以使用检查模式和静态分析工具提供的代码分析功能,提高代码健壮和安全性。
- 减少重复的代码。一个方法可以实现多种不同类型的作用。
泛型具体使用
方法
1 | T getRawData<T>(T value){ |
类
1 | class GetClass<T>{ |
接口
1 | abstract class Cache<T>{ |
库
内置库和包管理器提供的库pub
1
2
3import 'dart:io'; //内置库
import 'package:mylib/mylib.dart'; //包管理器库
import 'package:utils/utils.dart';导入库的一部分
1
2
3
4
5// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;延迟载入库
1
2
3
4
5
6
7
8
9//deferred as
import 'package:deferred/hello.dart' deferred as hello;
//使用库标识符调用 loadLibrary() 函数来加载库
//await 关键字暂停代码执行一直到库加载完成
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
异步流程
介绍
有两种方式可以使用 Future 对象中的 数据:
- 使用 async 和 await
- 使用 Future API
同样,从 Stream 中获取数据也有两种 方式:
- 使用 async 和一个 异步 for 循环 (await for)
- 使用 Stream API
使用
1 | checkVersion() async { |
可以使用 try, catch, 和 finally 来处理使用 await 的异常