Fork me on GitHub

Dart语法要点汇总

一个基础的Dart程序

[In]

1
2
3
4
5
6
7
8
9
10
11
12
13
// main为Dart程序入口
void main() {
// 调用printNumber方法
var number = 58;
printNumber(number);
}

// 方法返回类型缺省时,默认返回类型为dynamic
printNumber(int number) {
// 1. 字符串用单/双引号均可
// 2. 字符串中支持${}表达式, 单字符变量时可简化为$
print("The number is $number.");
}

[Out]

1
The number is 58.
  • Dart单行注释用//,多行注释用/**/(同Java)
  • var是一种不需要指定类型的声明方式
  • int是一种数据类型,对应的还有StringListbool类型
  • 字符串的标识用单、双引号均可(同Python、JS)
  • 字符串中支持${number}表达式, 单字符变量时可简化为$number(同JS的`${number}`

当你在学习Dart语言时,需要清楚这些概念:

  • 所有的东西都是一个对象,每个对象都是一个class的实例,即使是数字、函数、null都是对象,并且所有的对象都集成自Object类。
  • 尽管Dart语言是一种强类型语言,但你在类型声明时仍然可以不指定类型,因为Dart可以自动进行类型推断。在上面的代码中,number变量的类型就被推断为int,当你并不想显式地声明类型时,你可以使用指定的类型dynamic来标识。
  • Dart语言同样支持泛型,如List<int>List<dynamic>(同Java)。
  • Dart语言支持顶级方法(即不与类绑定的方法,如上的main方法),以及绑定类和实例的方法(分别对应静态方法和实例方法),而且还支持方法嵌套(同Python、JS)。
  • 和Java不同的是,Dart语言并不支持publicprotectedprivate这些关键字,它是通过前缀_来标识为私有域的(同Python),

变量

这是一个创建并初始化变量的例子

1
var name = 'Bob';

name变量类型被推断为String,你也能更改为指定的类型。如果一个变量的类型并不限制于单一类型,你也可以使用dynamicObject进行声明,如:

1
dynamic name = 'Bob';

同样也可以选择指定的声明方式

1
String name = 'Bob';

但根据Dart推荐的编码风格,在局部变量中使用var要更优于指定的类型声明。

默认值

Dart中声明时如果未初始化,会被自动初始化为null

1
2
int lineCount;
assert(lineCount == null);

注:assert只在开发环境有效,在实际的生产环境无效

final与const

finalconst标识该变量只能被赋值一次,区别在于final是运行时赋值,const是编译时赋值。

1
2
3
final String nickname = 'Jack';
// final修饰时, 可省略类型声明
final name = 'Jack';

const不仅可以用来声明变量,还能用来创建常量值,如:

1
2
// 此时不能在对列表a进行更新操作
var a = const [1, 2];

内置类型

数字型

包含intdouble,不包含float

常用的类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// String -> int
var a = int.parse('1');
assert(a == 1);

// String -> double
var b = double.parse('1.1');
assert(b == 1.1);

// int -> String
String c = 1.toString();
assert(c == '1');

// double -> String
String d = 3.14159.toStringAsFixed(2);
assert(d == '3.14');

字符串

  • 单引号、双引号均可

  • 字符串拼接时,换行可省略加号,如

    1
    2
    3
    4
    var a = '123'
    '456';
    print(a);
    // Out: 123456
  • 字符串可以用索引,但不支持负值索引(区分于Python),如

    1
    2
    3
    var a = 'Jack';
    print(a[1]);
    // Out: a

列表

在Dart语言中,数组即列表

[In]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void main() {
// 初始化
var list = ['a', 'b', 'c'];
// 增
list.add('d');
// 删
list.remove('b');
// 改
list[1] = 'cc';
// 查
var last = list[list.length - 1];
print('list is $list');
print('last is $last');
}

[Out]

1
2
list is [a, cc, d]
last is d

字典

[In]

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
var map = {'a': 1, 'b': 2};
// 增
map['c'] = 3;
// 删
map.remove('a');
// 改
map['b'] = 22;
// 查
var cValue = map['c'];
print('map is $map');
print('cValue is $cValue');
}

[Out]

1
2
map is {b: 22, c: 3}
cValue is 3

函数

Dart是一门完全面向对象的语言,即使它的函数也是一个对象,并且有自己的类型——Function。这就意味着函数可以被赋值为一个变量,或者作为一个参数在其他函数之间传递。

对于只包含一个表达式的方法体,你也可以使用=>的简写形式,如:

1
2
3
4
5
6
void say() {
print('123');
}

// 该写法与以上有同样效果
void say2() => print('123');

可选参数

Dart的可选参数分为命名可选参数位置可选参数两种(两者之间互斥,即不能同时使用)。

命名可选参数

[In]

1
2
3
4
5
6
7
void main() {
say(age: 27);
}

void say({String name='Jack', int age=20}) {
print('$name\'s age is $age.');
}

[Out]

1
Jack's age is 27.

位置可选参数

[In]

1
2
3
4
5
6
7
void main() {
say('Tom', 27, 'Love game.');
}

void say(String name, int age, [String remark]) {
print('$name\'s age is $age.${remark??''}');
}

[Out]

1
Tom's age is 27.Love game.

默认参数值

参数可用=声明默认值,默认值只能是编译时常量。

注:命名可选参数的默认参数值可使用:指定,但对于位置可选参数不支持,推荐统一使用=的默认参数指定方式

匿名函数

[In]

1
2
3
4
5
6
void main() {
var list = ['Android', 'iOS', 'WindowPhone'];
list.forEach((item) {
print(item);
});
}

[Out]

1
2
3
Android
iOS
WindowPhone

特殊操作符

  • a ~/ b <=> (a / b) as int

  • is <=> Java的instanceof

  • a?.b <=> a == null ? null : a.b

  • a??b <=> a == null ? b : a

  • a ??= b <=> a = a == null ? b : a

  • a as String <=> Java的(String) a

  • ..级联操作符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var button = querySelector('#confirm');
    button.text = 'Confirm';
    button.classes.add('important');
    button.onClick.listen((e) => window.alert('Confirmed!'));

    // 该写法等价上述写法
    querySelector('#confirm') // Get an object.
    ..text = 'Confirm' // Use its members.
    ..classes.add('important')
    ..onClick.listen((e) => window.alert('Confirmed!'));

异常

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
// 抛异常
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';

// 捕获异常
try {
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');
}

try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
// 第二个参数s是一个错误堆栈实例
print('Stack trace:\n $s');
}

try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
// 关键字rethrow重新抛出异常
rethrow; // Allow callers to see the exception.
}

重载操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Vector {
final int x, y;

Vector(this.x, this.y);

Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

// Operator == and hashCode not shown. For details, see note below.
// ···
}

void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);

assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}

生成器

  • sync* + yield返回Iterable对象
  • async* + yield返回Stream对象
1
2
3
4
5
6
7
8
9
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}

Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}

如果生成器返回值是可迭代的,亦可使用yield*来提高性能,如:

1
2
3
4
5
6
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}

可调用的类

给类定义call方法能使得当前类是Callable的(同Python)

1
2
3
4
5
6
7
8
9
class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}

main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
}

------------- The end -------------