Dart語言學(xué)習(xí)筆記

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
  1. 一切皆對象, 默認值為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()

  1. Dart程序都是沖main()函數(shù)執(zhí)行,
  2. 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');
}

簡寫

  1. 函數(shù)語句可以簡寫, 使用=>簡寫替代{ return expr; }
  2. 會自動推斷函數(shù)返回值, 返回值可以省略, 但是會有警告
    • 函數(shù)體中無return語句, 返回值為null
    int calculate() => 6 * 7;

    calculate2() => 6 * 7;

    main() => print('calculate result: ${calculate()}');

可選命名參數(shù), Named parameters

  1. 使用{}包裹
  2. 可以使用@required注解, 表示該參數(shù)一定要傳入; 使用該注解, 需要依賴meta包的package:meta/meta.dart
  3. 可以定義默認值, 不定義即為null
  4. 調(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

  1. 使用[]包裹
  2. 可以可以定義默認值, 不定義即為null
  3. 調(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ù)也是對象

  1. 函數(shù)都是Function的子類, 也可以作為參數(shù)傳遞
     void main(List<String> arguments) {
         ['a', 'b', 'c'].forEach(print);
     }
    

匿名函數(shù)

  1. 使用(parms){return expr;}格式
  2. 簡單函數(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

  1. 普通的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.....

  1. / Divide
  2. ~/ Divide, returning an integer result
  3. % 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;

條件語句

  1. 三元表達式 condition ? expr1 : expr2
  2. expr1 ?? expr2, 三元表達式判空簡寫, 和expr1 != null ? expr1 : expr2 作用相同

函數(shù)調(diào)用

  1. ?. 非空調(diào)用, 和kotlin一樣
  2. .. 級聯(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

  1. throw拋異常, 可以是任何對象

    throw FormatException('Expected at least 1 section');
    
    throw 'Out of llamas!';
    
  2. 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');
}

對象

變量

  1. 使用_開頭, 代表私有變量
  2. 默認有setter, getter方法, final類型沒有setter, 私有變量沒有gettter
  3. 有類型推斷, 可以使用var聲明
    1. var是動態(tài)類型, 后續(xù)可以改變類型, 類似聲明為Object
    2. 和聲明成Object不同的是, 可以使用實例相應(yīng)的方法, 而Object需要做相應(yīng)的類型轉(zhuǎn)換
    3. dynamicvar 好像不區(qū)分了, 目前沒找到相應(yīng)的文檔
  4. const為編譯試常量, 在Class中必須聲明成static

構(gòu)造方法

  1. 未聲明構(gòu)造方法時, 提供不含任何參數(shù)的構(gòu)造方法, 和Java類似
  2. 構(gòu)造方法不可以重置, 即有且僅有一個構(gòu)造方法

簡寫, 可以在構(gòu)造方法中直接賦值

class Point {
  num x, y;

  Point(this.x, this.y);
}
Default const
  1. Initializer list
    • 簡寫, 直接在方法體外面寫賦值語句
  2. Named constructors
    • 類似于Java中的static方法, 用于去創(chuàng)建對象, 感覺是對方法不可重載的折中
  3. Redirecting constructors
    • 調(diào)用自身的其他構(gòu)造方法
  4. 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生成自身實例
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)

  1. Dart的函數(shù), 不可重載
  2. interface是關(guān)鍵字, 沒有單獨的interface, 所有的class都是隱藏的interface
    1. 類似Java中的接口, 可以使用abstract classes代替
  3. 多重繼承mixins, 使用extends with 去繼承
    1. mixin的對象, 不能有構(gòu)造方法
    2. 如果mixin的對象, 不打算作為普通的對象去使用, 定義時 可以使用mixin關(guān)鍵字代替class

異步

Futrue / 協(xié)程

  1. 創(chuàng)建

    1. 使用async聲明一個異步調(diào)用的方法, async方法返回的是一個Future
    2. 使用Future的工廠方法, delayed,error, value...
  2. 使用

    1. async方法中, 可以使用awite獲取另一個async方法的返回值
    2. Future也可以使用then方法回調(diào)消費數(shù)據(jù), 詳細參考API文檔
    3. 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

  1. 創(chuàng)建

    1. 使用Stream自身的工廠方法去創(chuàng)建, eg Stream.empty(),fromIterable, fromFuture
    2. 使用async*方法創(chuàng)建, 使用yield傳遞值
    3. 使用StreamController創(chuàng)建
  2. 消費

    1. async方法中, 使用 await for(var in stream)進行消費
    2. 使用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');
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容