main
函数, print
函数内省.
void main() {
var name = "tom";
print("hello, ${name}");
}
dynamic
¶类型推断.
var name = "tom";
// ==
String name = "tom";
定义一个类型可变的变量.
dynamic name = "tom";
print("hello, ${name}");
name = 1;
print("int? ${name}");
所有变量都是引用, 因此所有类型默认值都是null
, 包括数值.
int x;
print("default int ${x}");
// default int null
num
int (64bit)
double (64bit)
string
utf-16
bool
true/false
list
var x = []
List<int> x = []
.length
x[i] = y
map
var m = {k: "v"}
Map<int, String> m = {}
.length
m["key"] = value
编译期常量, const
, static const
.
常(变)量.
const x = [];
常值.
final x = const [];
named 参数
positional 参数
optional 参数
int sum0({int x = 1, int y = 2}) {
return x + y;
}
int sum1(int x, int y, [int z = 4]) {
return x + y + z;
}
sum0(x: 1);
sum1(1, 2);
匿名函数:
([[Type] param1[,...]]) {
block;
};
var upper = (msg) => msg.toUpperCase();
var upper2 = (msg) {
return msg.toUpperCase();
};
Function
与词法闭包
的例子一起看
{}
Function makeAdder(int x) {
return (int i) => x + i;
}
var adder2 = makeAdder(2);
adder2(3); // == 5
~/
整除
?.
v?.x
如果v
不为null
, 访问x
字段. 可以避免exception.
??
expr1 ?? expr2
等价于py中的, expr1 or expr2
??=
b ??= value
如果b
为null
, 则赋值value, 否则什么都不做.
..
cascade
is
/is!
类型assert
a is TypeA
a ? b: c
可以抛出任何类型数据.
throw FormatException("");
throw 'ABC'
try {
} on XException {
} on YException {
} catch(e) {
}
这里catch
是默认handler.
rethrow
在handler里重新抛出已经handle的异常.
finally
永远执行, 不论有没有把异常抓住.
获取一个object的类型.
obj.runtimeType
构造函数不能被继承, named构造函数, 类似于工厂方法.
可以调用父类的构造函数(因为父类构造函数的创建时间先于子类).
class Employee extends Person {
Employee : super.fromJson(getDefaultData());
}
初始化列表,类似于c++.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
// code block
}
factory
机制引进的比较奇怪, 没想到太多好处. cache
应该显式的做.
可以针对某一类型, 提供mixin
.
mixin MusicalPerformer on Musician {}
使用with
应用.
class C extends A with E, F, G {}
TODO 多个mixin
中, 字段有重名怎么处理?
类似java的泛型.
class Foo<T extends Bar> {}
T add<T extends num>(T x, T y) {
return x + y;
}
add<int>(1, 2);
别名
import ‘xxx’ as bbb;
特定import
import ‘xxx’ show x;
排除import
import ‘xxx’ hide y;
import ‘xxx’ defered as y;
第一次需要的时候才会加载.
var s = "";
(s == null) == false;
s.isEmpty == true;
var sb = StringBuffer();
sb
..write("hello,")
..writeAll(["t", "o", "m"])
..writeln();
s = sb.toString();
s = ["hello", "world"].join(",");
一个整数生成器, 一个异步求和函数, 求得结果.
import 'dart:async';
Future<int> sumStream(Stream<int> s) async {
var sum = 0;
await for (var v in s) {
sum += v;
}
return sum;
}
Stream<int> countStream() async* {
for (int i = 0; i <= 1000; i++) {
yield i;
}
}
main() async {
var sum = await sumStream(countStream());
print(sum);
}
几个关键字async
, async*
, await
.
async
, async*
用于标注函数, 当函数体中包含await
, 那么这个函数就需要标注为async
.
async*
异步生成器, sync*
同步生成器.
两种
single subscription
只能被listen
一次.
broadcast
实际中能否简单的把stream和生成器等价?
https://webdev.dartlang.org/articles/performance/event-loop
实现异步代码的核心逻辑.
isolate
是dart中的一个控制单元, 其内部的代码顺序执行,拥有自己的内存. 多个isolate
之间内存是隔离的,也没有共享内存机制, 通信依靠Port
进行.
可以理解为一个Actor
的dart实现.