Kahn's blogs

学习Dart语言随手笔记

2019/03/04

dynamic关键字

1
2
3
4
5
6
7
/// Returns a Boolean representation for [arg], which must
/// be a String or bool.
bool convertToBool(dynamic arg) {
if (arg is bool) return arg;
if (arg is String) return arg == 'true';
throw ArgumentError('Cannot convert $arg to a bool.');
}

泛型

Dart支持泛型类型,如List(整数列表)或List(任何类型的对象列表)

基本类型转换

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');

多行字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
//第一种写法
var s1 = 'String '
'concatenation'
" works even over line breaks.";
//第二种写法
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";

原始字符串

1
var s = r'In a raw string, not even \n gets special treatment.';

list

1
2
3
4
5
6
7
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
var constantList = const [1, 2, 3];

map

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
1,
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
2,
var gifts = Map();
gifts['first'] = 'partridge';
var nobleGases = Map();
nobleGases[2] = 'helium';
3,
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
4,
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};

Function

Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function。 这意味着函数可以分配给变量或作为参数传递给其他函数。您也可以像调用函数一样调用Dart类的实例。有关详细信息,请参阅可调用类。

1
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

可选参数

1
2
3
4
5
6
7
8
9
10
定义
void enableFlags({bool bold, bool hidden}) {...}
调用
enableFlags(bold: true, hidden: false);
必须的参数
import package:meta/meta.dart
const Scrollbar({Key key, @required Widget child})

可选的位置参数

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;
}

默认参数值

1
2
3
4
5
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold will be true; hidden will be false.
enableFlags(bold: true);

函数当成参数传递(函数也是一个对象 Function对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
2
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');

闭包参数传值(相当于java中参数传入方法体中的匿名函数需要final)

方法体会持有外部参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}

makeAdder方法中的代码片段会持有外部传入的addBy

Type test operators

Operator Meaning
as Typecast (also used to specify library prefixes)
is True if the object has the specified type
is! False if the object has the specified type

??= 当值为空时,才赋值

expr1 ?? expr2

expr1为空才计算expr2

?. 当为空时,整个表达式结果为空

级联

1
2
3
4
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

for in

1
2
3
4
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}

try catch

throw

1
2
3
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';
void distanceTo(Point other) => throw UnimplementedError();

try

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
特定异常
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
先捕获特定异常,
然后捕获带异常对象的异常
最后捕获剩余的异常
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');
print('Stack trace:\n $s');
}
//重新抛出
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}

// If p is non-null, set its y value to 4.
p?.y = 4;

构造对象

1
2
3
4
5
6
7
var p1 = Point(2, 2);
//json构造
var p2 = Point.fromJson({'x': 1, 'y': 2});
//常量构造函数
var p = const ImmutablePoint(2, 2);

获取类型

1
print('The type of a is ${a.runtimeType}');

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Point {
num x, y;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
命名构造函数
class Point {
num x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}

子类不继承父类的构造函数

父类没有默认的构造函数,子类写自己的构造函数时,需要使用 :调用一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}

默认参数

1
2
3
4
5
6
7
8
9
10
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
//验证参数
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}

重定向构造函数

1
2
3
4
5
6
7
8
9
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}

常量构造函数

1
2
3
4
5
6
7
8
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}

工厂构造函数

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
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);
}
}
var logger = Logger('UI');
logger.log('Button clicked');

方法

get set

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);
// Define two calculated properties: right and 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);
}

接口

每个类既是类,又是接口,如果你想不使用类的实现,但是需要它的类型,就是使用implements,否则就extends

方法未实现时会被调用 noSuchMethod

1
2
3
4
5
6
7
8
9
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
mixins 语法(高级)
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
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
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');
}
}
}

泛型示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
To specify one or more types when using a constructor, put the types in angle brackets (<...>) just after the class name. For example:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
var nameSet = Set<String>.from(names);
var views = Map<int, View>();

打印泛型类型

1
2
3
4
5
6
class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}

导入库

库冲突

1
2
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

导入库的一部分

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
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}

async and await

要使用await 必须在标有async的函数上进行

1
2
3
4
5
6
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
Future<String> lookUpVersion() async => '1.0.0';

处理流

1
2
3
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}

Generators(迭代生成器)

  1. 同步的Generators

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

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

可调用的类

需要实现call方法

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
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');
}
```
### typedef
函数类型(函数式变成基础)
``` dart
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// Initial, broken implementation.
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}

定义元数据

示例

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');
}

https://www.dartlang.org/guides/language/language-tour