Dart基础语法(二)

Class

Dart是一个面向对象的语言,具有类和基于mixin的继承。每个对象都是一个class的实例,所有的class都是基于Object。

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
// 所有未初始化的变量都为null
class Point {
num x;
num y;
num z = 0;
num d;

// 构造函数
// Point(num x, num y) {
// this.x = x;
// this.y = y;
// }

// 更简便的写法
Point(this.x, this.y);

// 构造函数的明明
Point.origin() {
x = 0;
y = 0;
}
}

void main() {
var point = new Point(10, 20);
point.x = 4;
assert(point.x == 4);
assert(point.d == null);
}

构造函数

构造函数与继承

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
class Point {
var x;
var y;

// 简单的构造函数使用,相当于 Point(x, y) { this.x = x; this.y = y; }
Point(this.x, this.y);

// 在开发环境下可以用 assert对参数进行断言
Point.withAssert(this.x, this.y): assert(x>= 0) {
print('in person.withAssert(): ($x, $y)');
}

// 这一块的初始化列表有点像 java 还是 c++
Point.fromJson2(Map<String, num> json):
x = json['x'],
y = json['y'] {
print('In Person.fromJson2() : ($x, $y)');
}

// 内部使用构造函数
Point.alongXAxis(num x): this(x, 0);
}


getDefaultData() {}

class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}

class Employee extends Person {
Employee.fromJson(Map data): super.fromJson(data) {
print('in Employee');
}

// 因为调用构造函数之前会计算超类构造函数的参数,所以参数可以是一个表达式
Employee(): super.fromJson(getDefaultData());
}

main() {
var emp = new Employee.fromJson({});


if (emp is Person) {
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'bob';
}

常量构造函数

如果你的类不需要改变,你可以将他写成编译时常量,但是要确保所有的实例变量都是final

1
2
3
4
5
6
7
8
9
class ImmutablePoint {
static final ImmutablePoint origin = const ImmutablePoint(0, 0);
// 确保所有的实例变量都是 final
final num x, y;
const ImmutablePoint(this.x, this.y);
}
const a = ImmutablePoint(1,2);
const b = ImmutablePoint(1,2);
assert(a == b);

工厂构造函数

在实现并不总是创建其类的新实例的构造函数时,请使用factory关键字。例如,工厂构造函数可能从缓存中返回实例,或者它可能返回子类型的实例。

注意 工厂构造函数不能访问this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 工厂构造函数,不需要经常实例化的情况,会从缓存获取
class Logger {
final String name;
bool mute = false;

// _cache is library-private, thanks to the _ in front of its name.
static final Map<String, Logger> _cache = <String, Logger>{};

factory Logger(String name) {
if (_cache.containsKey(name)) return _cache[name];
else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}

Logger._internal(this.name);

void log(String msg) {
if (!mute) print(msg);
}
}

Methods(方法)

Instance methods(实例方法)

普通的实例方法

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

Point(this.x, this.y);

// 普通的方法
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}

Getters && Setters

1
2
3
4
5
6
7
8
9
10
class Rectangle {
num left, top, width, height;

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

num get right => left + width;
set right(num value)=> left = value - width;
num get bottom => top + height;
set bottom(num value)=> top = value - height;
}

Abstract methods/ Abstract Class

抽象类

1
2
3
4
5
6
7
abstract class Doer {
void doSomething(); // 定义了一个抽象方法
}

class EffectiveDoer extends Doer {
void doSomething() { print('xxx'); } // 实现该方法
}

Implicit interfaces

接口和java很像

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
// implicit interfaces

// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library
final _name;

// Not in the interface, since this is a constructor.
Person(this._name);

// In the interface
String greet(String who) => 'Hello, $who. I am $_name';
}

// an implementation of the Person interface.
class Impostor implements Person {
get _name => '';

String greet(String who)=> 'Hi $who. Do you know who I am?';
}

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

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

// 多个接口
class Point implements Comparable, Location {
//...
}

extending a class扩展继承

1
2
3
4
5
6
7
8
9
10
11
12
class Television {
void turnOn() {
print('television turnOn');
}
}

class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
print('SmartTelevision');
}
}

overriding members 重写方法

子类重写实例方法,但是有加和没加和什么区别呢?这个疑惑在stackoverflow有解答

@override just points out that the function is also defined in an ancestor class, but is being redefined to do something else in the current class. It’s also used to annotate the implementation of an abstract method. It is optional to use but recommended as it improves readability.

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

Overridable operators

重写操作符? 看看就好

Enumerated types

枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Color { red, green, blue }
enums() {
// 枚举类型: 表示固定数量的常数值
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('red');
break;
default:
print(aColor);
}
}

mixins

mixins使用with关键字,Class TAS = A with S,则 TAS包含了所有AS的方法属性,以S为最终覆盖,即如果A与S有相同的方法,则S覆盖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
class S {
a() { print('S.a'); }
}
class A {
a() { print('A.a'); }
b() { print('A.b'); }
}
class B {
a() { print('B.a'); }
b() { print('B.b'); }
c() { print('B.c'); }
}

class TAS = A with S;
class TBAS = B with A, S;

void main() {
TAS t = new TAS();
t.a(); // S.a
t.b(); // A.b
TBAS b = new TBAS();
b.a(); // S.a
b.b(); // A.b
b.c(); // B.c
}

Class variables and methods

静态方法与静态属性static关键字实现

1
2
3
4
5
6
7
8
9
class Queue {
static const name = 'queue';

static num log(String str) {
print(str);
}
}

Queue.log(Queue.name);

Generics 泛型

泛型这块后面用到的话还要补,确实不是很熟

1
2
3
4
var name = List<String>();
// 等于 var names = <String>[];
name.addAll(['a','b']);
name.add(2); // 报错

类型限制

1
2
3
4
5
6
7
8
9
var names = <String>['a', 'b', 'c']; // list
var uniqueNames = <String>{'a', 'b', 'c'}; // set
var pages = <String, String> {
'index.html': 'homePage',
} // map
var nameSet = Set<String>.from(names);
var newMap = Map<int, String>();

print(names is List<String>); // true

Libraries

引入用import关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 引入
import 'dart:html';
import 'package:test/test.dart';

// 为某个库指定别名,jser比较喜欢这种,不会全局变量到处飘!
import 'package:lib/lib.dart' as lib;

// 局部引入
import 'package:lib/lib.dart' show foo; // 只引入foo
import 'package:lib/lib.dart' hide foo; // 除了foo其他都引入

// 懒加载
import 'package:greetings/hello.dart' deferred as hello;

Future greet() async {
await hello.loadLibrary(); // 先加载 loadLibrary会返回一个Future
hello.printGreeting(); // 再使用
}

创建一个库

create library packages

asynchrony support 异步支持

Dart一般用FutureStream来处理异步。

handling Futures

Future

使用await/async,所以Futures类似jsPromise?

1
2
3
4
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}

声明异步函数

如果函数没有返回值,则返回类型为 Future<void>.

1
2
String lookUpVersion() => '1.0.0';
Future<String> lookUpVersion() async => '1.0.0';

Handling Streams

使用 asyncawait for

1
2
3
4
5
6
7
// 1. 等待流的每一次值
// 2. 执行for循环的主体
// 3. 重复1和2直到流结束
// 4. 如果要中断流监听,可以用 break 或 return
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}

Generators

emmm js最讨厌的语法来到Dart还是无法避免,之前处理异步都是promise要不就是await

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 同步Generators
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}

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

// 如果你的Generator是递归的,可以用 yield*来优化
// 怎么优化呢?尾调用优化?
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}

Callable classes 可调用类

要实现类和方法一样的调用,则在类里面实现 call方法.

1
2
3
4
5
6
7
8
class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}
void main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
}

Typedefs

1
2
3
4
5
6
7
typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {
assert(sort is Compare<int>); // True!
}