Dart
基于2.7.2的版本
API參考[https://api.dart.dev/stable/2.8.0/index.html]
官方指導(dǎo)[https://dart.dev/guides/language/language-tour]
Built-in types
- numbers (int, double)
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
- 一切皆對象, 默認值為null (eg.numbers)
int a = 1;
double b = 1.0;
num c = 1;
String d = 'string';
bool e = true;
List<int> list = [1, 2, 3];
List<Object> list2 = [1, 'a'];
var map = {'a': 'b', 'c': 1};
var set = {1, 'a', 2};
void main(List<String> arguments) {
dynamic a = 'abcde';
Object b = 'abc';
var testType;
testType = 123;
testType = 'abc';
print('length: ${testType.length}');
print('length: ${(b as String).length}');
}
Function
main()
- Dart程序都是沖main()函數(shù)執(zhí)行,
-
main()返回void, 有個可選的參數(shù)List<String>
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
簡寫
- 函數(shù)語句可以簡寫, 使用
=>簡寫替代{ return expr; } - 會自動推斷函數(shù)返回值, 返回值可以省略, 但是會有警告
- 函數(shù)體中無
return語句, 返回值為null
- 函數(shù)體中無
int calculate() => 6 * 7;
calculate2() => 6 * 7;
main() => print('calculate result: ${calculate()}');
可選命名參數(shù), Named parameters
- 使用
{}包裹 - 可以使用
@required注解, 表示該參數(shù)一定要傳入; 使用該注解, 需要依賴meta包的package:meta/meta.dart - 可以定義默認值, 不定義即為
null - 調(diào)用時,使用
paramName:value傳入?yún)?shù), 可以不按順序
String sayHello(String from, {String msg}) {
return '${from} say hello, ${msg}';
}
void main(List<String> arguments) {
print(sayHello('Bob'));
print(sayHello('Bob', msg: "I'm Bob ~"));
}
可選位置參數(shù), Positional parameters
- 使用
[]包裹 - 可以可以定義默認值, 不定義即為
null - 調(diào)用時, 即使有默認值, 傳入?yún)?shù)時, 也不能跳過
String say(String from, String msg, [String device='Mac']) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
函數(shù)也是對象
- 函數(shù)都是
Function的子類, 也可以作為參數(shù)傳遞void main(List<String> arguments) { ['a', 'b', 'c'].forEach(print); }
匿名函數(shù)
- 使用
(parms){return expr;}格式 - 簡單函數(shù)體, 也可以使用
=>簡寫
void testLambda(int fun(int a, int b)) {
print(fun(3, 6));
}
void main() {
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
}
可調(diào)用類 callable class
- 普通的class可以添加
call方法, 作為callable class當做一個函數(shù), 直接調(diào)用
class PrintWrapper {
void call(var message) {
print(message.toString());
}
}
void main(List<String> arguments) {
var printWrapper = PrintWrapper();
printWrapper("this is message");
}
操作符, operators
算數(shù)操作符
++var, var--, -expr.....
- / Divide
- ~/ Divide, returning an integer result
- % Get the remainder of an integer division (modulo)
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder
比較
==, >, !=....
類型判斷
as, is, is!
(emp as Person).firstName = 'Bob';
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
賦值
// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;
條件語句
- 三元表達式
condition ? expr1 : expr2 -
expr1 ?? expr2, 三元表達式判空簡寫, 和expr1 != null ? expr1 : expr2作用相同
函數(shù)調(diào)用
-
?.非空調(diào)用, 和kotlin一樣 -
..級聯(lián)操作, 類似于kotlin中的apply, 其中的this即為前一個對象
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
操作符重載
class Point {
var x, y = 0;
Point(num x, num y) {
this.x = x;
this.y = y;
}
@override
bool operator ==(other) {
if (other is Point) {
return x == other.x && y == other.y;
}
return false;
}
Point operator +(Point p) {
return Point(x + p.x, y + p.y);
}
}
異常 try catch finally
-
throw拋異常, 可以是任何對象throw FormatException('Expected at least 1 section'); throw 'Out of llamas!'; catch捕獲所有異常,on捕獲指定異常
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');
}
對象
變量
- 使用
_開頭, 代表私有變量 - 默認有
setter,getter方法,final類型沒有setter, 私有變量沒有gettter - 有類型推斷, 可以使用
var聲明-
var是動態(tài)類型, 后續(xù)可以改變類型, 類似聲明為Object - 和聲明成
Object不同的是, 可以使用實例相應(yīng)的方法, 而Object需要做相應(yīng)的類型轉(zhuǎn)換 -
dynamic和var好像不區(qū)分了, 目前沒找到相應(yīng)的文檔
-
- const為編譯試常量, 在Class中必須聲明成static
構(gòu)造方法
- 未聲明構(gòu)造方法時, 提供不含任何參數(shù)的構(gòu)造方法, 和Java類似
- 構(gòu)造方法不可以重置, 即有且僅有一個構(gòu)造方法
簡寫, 可以在構(gòu)造方法中直接賦值
class Point {
num x, y;
Point(this.x, this.y);
}
Default const
- Initializer list
- 簡寫, 直接在方法體外面寫賦值語句
- Named constructors
- 類似于Java中的
static方法, 用于去創(chuàng)建對象, 感覺是對方法不可重載的折中
- 類似于Java中的
- Redirecting constructors
- 調(diào)用自身的其他構(gòu)造方法
- Factory constructors
- 構(gòu)造方法前, 使用
factory關(guān)鍵字修飾 - 工廠方法的語法糖, 內(nèi)部可以自己實現(xiàn)邏輯, eg.實現(xiàn)一個簡單工廠
- 方法體類, 沒有
this指針, 需要主動構(gòu)造此對象的實例并返回 - 屬于構(gòu)造方法, 由于構(gòu)造方法不能重置,因此只能調(diào)用
Named constructors生成自身實例
- 構(gòu)造方法前, 使用
class Point {
var x, y = 0;
Point(num x, num y) {
this.x = x;
this.y = y;
}
// Initializer list
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y']{}
// Named constructors
Point.origin() {
x = 0;
y = 0;
}
// Redirecting constructors
Point.originWithX(num x) : this(x, 0);
}
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) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
封裝、繼承、多態(tài)
- Dart的函數(shù), 不可重載
-
interface是關(guān)鍵字, 沒有單獨的interface, 所有的class都是隱藏的interface- 類似Java中的接口, 可以使用
abstract classes代替
- 類似Java中的接口, 可以使用
- 多重繼承
mixins, 使用extendswith去繼承- mixin的對象, 不能有構(gòu)造方法
- 如果mixin的對象, 不打算作為普通的對象去使用, 定義時 可以使用
mixin關(guān)鍵字代替class
異步
Futrue / 協(xié)程
-
創(chuàng)建
- 使用
async聲明一個異步調(diào)用的方法,async方法返回的是一個Future - 使用
Future的工廠方法,delayed,error,value...
- 使用
-
使用
- 在
async方法中, 可以使用awite獲取另一個async方法的返回值 -
Future也可以使用then方法回調(diào)消費數(shù)據(jù), 詳細參考API文檔 -
Future的靜態(tài)方法,any(),forEach,wait等可以對多個Future進行操作
- 在
import 'dart:io';
Future<String> getVersion() async {
sleep(Duration(seconds: 1));
return '2.7.2';
}
printVersion() async{
var version = await getVersion();
return print('version: $version');
}
main() {
getVersion().then((version) => print('then version: $version'));
printVersion();
print('----');
sleep(Duration(seconds: 5));
}
Stream
類似一個生產(chǎn)者/消費者; 上游生產(chǎn)數(shù)據(jù), 下游消費, 并且有一次類似Rx的操作符(eg. map, take...), 用于下游做數(shù)據(jù)處理轉(zhuǎn)換;
類似Rx,
- Observable對應(yīng)Stream;
- ObservableEmitter對應(yīng)StreamSink
- Observable.subscribe()方法對應(yīng)Stream.listen()
- Disposable對應(yīng)StreamSubscription; 不過StreamSubscription支持數(shù)據(jù)流的pause,resume; 感覺融合的Rx的backpress
-
創(chuàng)建
- 使用Stream自身的工廠方法去創(chuàng)建, eg
Stream.empty(),fromIterable,fromFuture - 使用
async*方法創(chuàng)建, 使用yield傳遞值 - 使用
StreamController創(chuàng)建
- 使用Stream自身的工廠方法去創(chuàng)建, eg
-
消費
- 在
async方法中, 使用await for(var in stream)進行消費 - 使用
listen方法
- 在
// Stream 工廠方法創(chuàng)建
Stream<String> createStringStream() {
var list = ['a', 'b', 'c'];
return Stream.fromIterable(list);
}
// async* 創(chuàng)建Stream
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) {
await Future.delayed(Duration(seconds: 1));
yield k++;
}
}
// StreamController創(chuàng)建Stream
Stream<int> timedCounter(Duration interval, [int maxCount]) {
StreamController streamController;
Timer timer;
int counter = 0;
void tick(_) {
counter++;
streamController.add(counter); // 使用add 發(fā)送一個數(shù)據(jù)
if (counter == maxCount) {
timer.cancel();
streamController.close(); // 關(guān)閉stream
}
}
void startTimer() {
timer = Timer.periodic(interval, tick);
}
void stopTimer() {
timer?.cancel();
timer = null;
}
streamController = StreamController<int>(
onListen: startTimer,
onResume: startTimer,
onPause: stopTimer,
onCancel: stopTimer);
return streamController.stream;
}
main() async {
createStringStream().forEach(print);
asynchronousNaturalsTo(3).forEach(print);
var subsucription = timedCounter(Duration(seconds: 1)).listen(print);
Future.delayed(Duration(seconds: 3), () {
subsucription.cancel();
});
await for (var i in timedCounter(Duration(seconds:2), 5)){
print('await for stream: $i');
}
}