0%

dart-第一章

变量

var -声明的变量不用指定变量类型
const 修饰类中的变量,则必须加上 static 关键字
final 修饰的是运行时的常量
const 修饰的是编译时的常量
变量名加下划线是私有的,以下划线(_)开头的成员仅在代码库中可见

类型转换

// String -> int
var one = int.parse(‘1’);
// String -> double
var onePointOne = double.parse(‘1.1’);
// int -> String
String oneAsString = 1.toString();
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);

可选参数

  • 命名参数
    void enableFlags({bool bold, bool hidden}) {…}

  • 位置参数
    使用 [] 将一系列参数包裹起来作为位置参数

    1
    2
    3
    4
    5
    6
    7
    String say(String from, String msg, [String device]) {
    var result = '$from says $msg';
    if (device != null) {
    result = '$result with a $device';
    }
    return result;
    }
  • 默认参数
    可以用 = 为函数的命名和位置参数定义默认值,默认值必须为编译时常量,没有指定默认值的情况下默认值为 null。

    1
    void enableFlags({bool bold = false, bool hidden = false}) {...}

级联运算符(..)

级联运算符(..)可以让你在同一个对象上连续调用多个对象的变量或方法。

1
2
3
4
querySelector('#confirm') // 获取对象 (Get an object).
..text = 'Confirm' // 使用对象的成员 (Use its members).
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

返回值

所有的函数都有返回值。没有显示返回语句的函数最后一行默认为执行 return null;。

条件表达式

如果赋值是根据布尔表达式则考虑使用 ?:。

1
var visibility = isPublic ? 'public' : 'private';
1
2
如果赋值是根据判定是否为 null 则考虑使用 ??。
String playerName(String name) => name ?? 'Guest';

获取对象的类型

可以使用 Object 对象的 runtimeType 属性在运行时获取一个对象的类型,该对象类型是 Type 的实例。

子类调用父类的构造函数

1
2
3
4
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}

初始化列表

除了调用父类构造函数之外,还可以在构造函数体执行之前初始化实例变量。每个实例变量之间使用逗号分隔。

1
2
3
4
5
6
7
8
// Initializer list sets instance variables before
// the constructor body runs.
// 使用初始化列表在构造函数体执行前设置实例变量。
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}

重定向构造函数

有时候类中的构造函数会调用类中其它的构造函数,该重定向构造函数没有函数体,只需在函数签名后使用(:)指定需要重定向到的其它构造函数即可:

1
2
3
4
5
6
7
8
9
class Point {
num x, y;

// 该类的主构造函数。
Point(this.x, this.y);

// 委托实现给主构造函数。
Point.alongXAxis(num x) : this(x, 0);
}

Getter 和 Setter

Getter 和 Setter 是一对用来读写对象属性的特殊方法,上面说过实例对象的每一个属性都有一个隐式的 Getter 方法,如果为非 final 属性的话还会有一个 Setter 方法,你可以使用 get 和 set 关键字为额外的属性添加 Getter 和 Setter 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Rectangle {
num left, top, width, height;

Rectangle(this.left, this.top, this.width, this.height);

// 定义两个计算产生的属性:right 和 bottom。
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}

void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}

抽象类

1
2
3
4
5
6
7
8
// This class is declared abstract and thus
// can't be instantiated.
// 该类被声明为抽象的,因此它不能被实例化。
abstract class AbstractContainer {
// 定义构造函数、字段、方法等……

void updateChildren(); // 抽象方法。
}

隐式接口

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
// A person. The implicit interface contains greet().
// Person 类的隐式接口中包含 greet() 方法。
class Person {
// _name 变量同样包含在接口中,但它只是库内可见的。
final _name;

// 构造函数不在接口中。
Person(this._name);

// greet() 方法在接口中。
String greet(String who) => '你好,$who。我是$_name。';
}

// Person 接口的一个实现。
class Impostor implements Person {
get _name => '';

String greet(String who) => '你好$who。你知道我是谁吗?';
}

String greetBob(Person person) => person.greet('小芳');

void main() {
print(greetBob(Person('小芸')));
print(greetBob(Impostor()));
}

扩展一个类

使用 extends 关键字来创建一个子类,并可使用 super 关键字引用一个父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}

class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}

重写类成员

子类可以重写父类的实例方法、Getter 以及 Setter 方法。你可以使用 @override 注解来表示你重写了一个成员

1
2
3
4
5
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}

枚举类型

枚举类型是一种特殊的类型,也称为 enumerations 或 enums,用于定义一些固定数量的常量值。

1
enum Color { red, green, blue }

使用 Mixin 为类添加功能

定义一个类继承自 Object 并且不为该类定义构造函数,这个类就是 Mixin 类,除非你想让该类与普通的类一样可以被正常地使用,否则可以使用关键字 mixin 替代 class 让其成为一个单纯的 Mixin 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;

void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}

Mixin 是一种在多重继承中复用某个类中代码的方法模式。
使用 with 关键字并在其后跟上 Mixin 类的名字来使用 Mixin 模式:

1
2
3
4
5
6
7
8
9
10
11
class Musician extends Performer with Musical {
// ···
}

class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}

可以使用关键字 on 来指定哪些类可以使用该 Mixin 类,比如有 Mixin 类 A,但是 A 只能被 B 类使用,则可以这样定义 A:

1
2
3
mixin MusicalPerformer on Musician {
// ···
}

使用集合字面量

1
2
3
4
5
6
7
var names = <String>['小芸', '小芳', '小民'];
var uniqueNames = <String>{'小芸', '小芳', '小民'};
var pages = <String, String>{
'index.html': '主页',
'robots.txt': '网页机器人提示',
'humans.txt': '我们是人类,不是机器'
};

限制参数化类型

1
2
3
4
5
6
class Foo<T extends SomeBaseClass> {
// 具体实现……
String toString() => "'Foo<$T>' 的实例";
}

class Extender extends SomeBaseClass {...}

这时候就可以使用 SomeBaseClass 或者它的子类来作为泛型参数:

1
2
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();

使用泛型方法

1
2
3
4
5
6
T first<T>(List<T> ts) {
// 处理一些初始化工作或错误检测……
T tmp = ts[0];
// 处理一些额外的检查……
return tmp;
}

指定库前缀

如果你导入的两个代码库有冲突的标识符,你可以为其中一个指定前缀。比如如果 library1 和 library2 都有 Element 类,那么可以这么处理:

1
2
3
4
5
6
7
8
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// 使用 lib1 的 Element 类。
Element element1 = Element();

// 使用 lib2 的 Element 类。
lib2.Element element2 = lib2.Element();

异步函数

  • Future

    1
    2
    3
    4
    Future checkVersion() async {
    var version = await lookUpVersion();
    // 使用 version 继续处理逻辑
    }
  • Stream

使用 async 关键字和一个 异步循环(使用 await for 关键字标识)。

1
2
3
4
5
6
7
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}

生成器(Generators

当你需要延迟地生成一连串的值时,可以考虑使用 生成器函数。Dart 内置支持两种形式的生成器方法:

同步 生成器:返回一个 Iterable 对象。

异步 生成器:返回一个 Stream 对象。

通过在函数上加 sync* 关键字并将返回值类型设置为 Iterable 来实现一个 同步 生成器函数,在函数中使用 yield 语句来传递值:

1
2
3
4
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}

实现 异步 生成器函数与同步类似,只不过关键字为 async* 并且返回值为 Stream:

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

元数据

使用元数据可以为代码增加一些额外的信息。元数据注解以 @ 开头,其后紧跟一个编译时常量(比如 deprecated)或者调用一个常量构造函数。

1
2
3
4
5
6
7
8
9
10
class Television {
/// _弃用: 使用 [turnOn] 替代_
@deprecated
void activate() {
turnOn();
}

/// 打开 TV 的电源。
void turnOn() {...}
}

可以自定义元数据注解。下面的示例定义了一个带有两个参数的 @todo 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
library todo;

class Todo {
final String who;
final String what;

const Todo(this.who, this.what);
}


import 'todo.dart';

@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}

-------------本文结束感谢你的阅读---------