在Dart中一切都是对象,一个.dart文件可以声明任何对象,包括类、函数、变量;
var
除了局部变量建议用var之外,其余地方建议用具体类型声明;
const
const 修饰一个编译时常量。
- 当修饰构造函数时,则该类的所有fields必须是final修饰;
- 当const修饰的是类的field,则必须同时修饰static;
- 被final或者const修饰的变量,变量类型可以省略;
final
类的fields被final修饰,可以不初始化(只是会警告),但是若要初始化,则必须通过构造函数来初始化,不能通过其它函数初始化。
- 声明对象时可以省略对象类型;
covariant
因为Dart是类型安全的,所以Override方法时,方法的参数类型不能“收缩(tight)”。但是某些时候需要这种情况时,可以用该关键字注解用来抑制「静态检测错误」(即使知道是无效的),以 通过编译。但是运行时仍会执行无效参数检查。
Class
dart文件
- 主方法是
main()
, 如果需要接收输入的参数则定义为main(List<String> args)
; - 可以定义任何代码,包括多个类、变量、函数等,无需限定在
class
内部; 没有
public、protected、private
关键字,默认所有的定义都是「public」的,如果需要转化为「private」,直接在对应的命名前增加下划线_
;abstract
定义抽象类,使用extends
则表示继承;没有
interface
关键字,默认所以的class
都是隐式的接口。使用implements
实现接口:- 若在同一个文件,则必须实现接口定义的所有变量和函数;
- 若不在同一个文件,则只需实现「public」类型的变量和函数;
构造函数
提供两种定义方式:
与类名
(ClassName)
相同,可以理解为NoNamed constructors
;有且只能存在一个
以
ClassName.identifier
的形式,称作Named constructors
;可用以提供更具场景化的构造名称,和Java的利用静态方法构造对象的方案类似,因此这种构造方式也就无法被子类继承;
在没有显式提供任何构造函数时,默认包含一个 无参无名 构造函数;不管是哪种方式,一旦显式定义了,默认的无参构造函数就被取代;
可以没有方法体;
构造函数参数区后可继续接
:
+ 表达式,称为初始化表达式Initializer expressions
:- 调用父类构造函数,例如:
Point.circle(int x) : super.any(x);
- 实例化成员变量,例如:
Point(int y) : x = 1 + y;
- 开发阶段的断言,例如:
Point(int y) : assert(y > 0);
重定向到其它构造函数,例如:
Point.circle(int x) : this(x);
重定向无法和上述前三种共用、没有body、不能快速参数指定
1, 2, 3可以组合,但是1必须位于整个表达式的最后。
- 调用父类构造函数,例如:
factory
关键字定义一个工厂函数(是构造函数,相当于从语言层支持了工厂方法),例如抽象类不能被实例化,可以利用该方式返回子类对象;如果类实例化的对象不可变(不可修改该对象、且不可修改该对象的变量),可以通过在构造函数前面声明
const
、对所有变量声明final
来将对象转化为编译时常量。该形式的构造函数有以下特性:
- 没有有body;
- 由于所有的变量必须final,对于私有变量,可以通过 初始化表达式 来实例化;
- 初始化表达式 涉及的只能是常量;
- 任何地方通过该构造函数实例化的 constant对象 (例如
const Point(1)
这种),如果参数完全一致,那么这些对象是同一个对象;
1. 参数
- 可直接在参数区使用
this.
+ 实例变量名 快速为实例变量赋值,例如:1
Bicycle(this.cadence, this.speed, this.gear);
命名可选参数:将构造函数的部分参数包裹在
{}
中,同时可以为可选参数提供默认值,若参数是一个对象,则默认值需要声明为const
以表示是一个编译时常量;位置可选参数:将构造函数的部分参数包裹在
[]
中,传入的参数位置和函数声明的参数位置一一对应。
2. 继承
- 子类的构造函数必须调用父类的构造函数,默认隐式调用父类的无参无名构造函数(注意:
Named constructors
的无参构造函数不算);若父类没有,则需要通过: super
的形式手动调用,例如:1
Point.circle(int x) : super(x);
实例
- 定义对象时可以使用
var
关键字,同时也支持final
(如果该对象不会发生变化); - 实例化对象时可以省略
new
关键字;
变量
由于完全面向对象,所以任何类型的变量默认值都为null,即使是num;
默认情况每个「public」实例变量都隐式地实现了
getter/setter
(无需也禁止再手动实现),如果该实例变量被声明为了「private」,则可以使用关键字get
定义方法以提供对外(内)访问,set
定义方法提供对外(内)修改;
泛型
- 与Java的泛型在运行时被擦除不一样的是,Dart的泛型指定后在运行时始终存在:
1
2
3var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
Mixin
- 可以理解为「组合」,形如Java接口但更强大;
- 使用方式是通过
class A with B, C, ...
,使A得到B、C的方法、字段; 除了普通类,可使用关键字
mixin
定义一种特殊的类,专门表示用来mixin(with
)的;- mixin类不能继承或被继承,但是可以(或被)
implements
; - mixin类可以后接
on
,例如mixin A on B
,用以限定 A 只能被 B 及其子类所with
; - mixin on 所指定的限定类必须包含一个无参无名构造函数;
- mixin类不能继承或被继承,但是可以(或被)
异常
try-catch-finally
捕获异常;可以在try模块后接
on + Ex
模块来捕获具体类型的异常,区别于catch
捕获的是具体异常对象;1
2
3
4
5
6
7
8
9
10
11
12try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}使用
throw
+ 字符串 快速抛出异常,也可以继承Exception
类实现自定义的异常;- 使用
reThrow
快速在catch块中再次抛出;
函数式编程
- 支持函数作为参数;
- 支持将函数赋值给变量;
由于函数也是对象,所以关键字
Function
如同num、bool
一样,代表函数的类型,因此,对象可声明的地方,函数也如此,例如:1
2
3
4
5void main() {
Function test() {
return int abc() => 0;
}
}所有的函数都有返回值,如果没有显式指定return,默认返回null;
- 函数可以省略声明返回类型,这样就是默认的dynamic类型;
=> expr
是对{ return expr; }
的一种简写手法,注意:expr指表达式;
typedef
- 也是一种类型;
typedef 用于定义Function类型,具体指参数类型、个数、返回值,而Function的名字只是一个别名,包括以下两种定定义方式:
typedef XXX = void Function(int/String/... x);
typedef void XXX(int/String/... x);
注意:若省略参数名,则参数类型失效,变为了dynamic
1 | typedef int Test(Object a, Object); |
条件
switch case
支持省略break
以继续下一个case
,但是前提是这个case
不包含代码,否则异常;如果确要如此,可以使用continue + label:
的形式:1
2
3
4
5
6
7
8
9
10
11
12switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
external
大意是用于修饰函数,表示该函数的具体实现和它定义的地方是分开的。据目前所知,这种形式常用来针对不同平台作不同的具体实现,例如浏览器端和服务端VM的差异实现。
async / await
https://segmentfault.com/a/1190000007535316
sync/async/yield/yield*
一种(序列)生成器的概念。https://www.dartlang.org/articles/language/beyond-async
类似Async-await概念。用Sync/Async修饰函数,函数被调用时,不同于前者立即返回Future,后者是返回Iterable(同步)/Stream(异步)。
函数内通过yield发射值到迭代器/流,同步的情况是需要外部pull(惰性);异步的情况是stream被订阅后主动push;
- Sync、ASync是同步和异步的区别,同步情况下,每次yield后会“暂停”,直到下次被pull;异步情况则不会。
- yield后接一个表达式,yield* 则是后接一个子序列(符合同步异步情况的前提下),并将这个子序列转入当前函数的序列中。