Dart语言学习笔记

Dart

基于2.7.2的版本

API参考[https://api.dart.dev/stable/2.8.0/index.html]
官方指导[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()函数执行,
  2. main()返回void, 有个可选的参数List<String>
void main(List<String> arguments) {
  print(arguments);

  assert(arguments.length == 2);
  assert(int.parse(arguments[0]) == 1);
  assert(arguments[1] == 'test');
}

简写

  1. 函数语句可以简写, 使用=>简写替代{ return expr; }
  2. 会自动推断函数返回值, 返回值可以省略, 但是会有警告
    • 函数体中无return语句, 返回值为null
    int calculate() => 6 * 7;

    calculate2() => 6 * 7;

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

可选命名参数, Named parameters

  1. 使用{}包裹
  2. 可以使用@required注解, 表示该参数一定要传入; 使用该注解, 需要依赖meta包的package:meta/meta.dart
  3. 可以定义默认值, 不定义即为null
  4. 调用时,使用paramName:value传入参数, 可以不按顺序
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 ~"));
}

可选位置参数, Positional parameters

  1. 使用[]包裹
  2. 可以可以定义默认值, 不定义即为null
  3. 调用时, 即使有默认值, 传入参数时, 也不能跳过
String say(String from, String msg, [String device='Mac']) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

函数也是对象

  1. 函数都是Function的子类, 也可以作为参数传递
     void main(List<String> arguments) {
         ['a', 'b', 'c'].forEach(print);
     }
    

匿名函数

  1. 使用(parms){return expr;}格式
  2. 简单函数体, 也可以使用=>简写
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');
  });
}

可调用类 callable class

  1. 普通的class可以添加call方法, 作为callable class当做一个函数, 直接调用
class PrintWrapper {
  void call(var message) {
    print(message.toString());
  }
}

void main(List<String> arguments) {
  var printWrapper = PrintWrapper();
  printWrapper("this is message");
}

操作符, operators

算数操作符

++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 作用相同

函数调用

  1. ?. 非空调用, 和kotlin一样
  2. .. 级联操作, 类似于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是动态类型, 后续可以改变类型, 类似声明为Object
    2. 和声明成Object不同的是, 可以使用实例相应的方法, 而Object需要做相应的类型转换
    3. dynamicvar 好像不区分了, 目前没找到相应的文档
  4. const为编译试常量, 在Class中必须声明成static

构造方法

  1. 未声明构造方法时, 提供不含任何参数的构造方法, 和Java类似
  2. 构造方法不可以重置, 即有且仅有一个构造方法

简写, 可以在构造方法中直接赋值

class Point {
  num x, y;

  Point(this.x, this.y);
}
Default const
  1. Initializer list
    • 简写, 直接在方法体外面写赋值语句
  2. Named constructors
    • 类似于Java中的static方法, 用于去创建对象, 感觉是对方法不可重载的折中
  3. Redirecting constructors
    • 调用自身的其他构造方法
  4. Factory constructors
    • 构造方法前, 使用factory关键字修饰
    • 工厂方法的语法糖, 内部可以自己实现逻辑, eg.实现一个简单工厂
    • 方法体类, 没有this指针, 需要主动构造此对象的实例并返回
    • 属于构造方法, 由于构造方法不能重置,因此只能调用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);
  }
}

封装、继承、多态

  1. Dart的函数, 不可重载
  2. interface是关键字, 没有单独的interface, 所有的class都是隐藏的interface
    1. 类似Java中的接口, 可以使用abstract classes代替
  3. 多重继承mixins, 使用extends with 去继承
    1. mixin的对象, 不能有构造方法
    2. 如果mixin的对象, 不打算作为普通的对象去使用, 定义时 可以使用mixin关键字代替class

异步

Futrue / 协程

  1. 创建

    1. 使用async声明一个异步调用的方法, async方法返回的是一个Future
    2. 使用Future的工厂方法, delayed,error, value...
  2. 使用

    1. async方法中, 可以使用awite获取另一个async方法的返回值
    2. Future也可以使用then方法回调消费数据, 详细参考API文档
    3. Future的静态方法,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

类似一个生产者/消费者; 上游生产数据, 下游消费, 并且有一次类似Rx的操作符(eg. map, take...), 用于下游做数据处理转换;
类似Rx,
- Observable对应Stream;
- ObservableEmitter对应StreamSink
- Observable.subscribe()方法对应Stream.listen()
- Disposable对应StreamSubscription; 不过StreamSubscription支持数据流的pause,resume; 感觉融合的Rx的backpress

  1. 创建

    1. 使用Stream自身的工厂方法去创建, eg Stream.empty(),fromIterable, fromFuture
    2. 使用async*方法创建, 使用yield传递值
    3. 使用StreamController创建
  2. 消费

    1. async方法中, 使用 await for(var in stream)进行消费
    2. 使用listen方法
// Stream 工厂方法创建
Stream<String> createStringStream() {
  var list = ['a', 'b', 'c'];
  return Stream.fromIterable(list);
}

// async* 创建Stream
Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;

  while (k < n) {
    await Future.delayed(Duration(seconds: 1));
    yield k++;
  }
}

// StreamController创建Stream
Stream<int> timedCounter(Duration interval, [int maxCount]) {
  StreamController streamController;
  Timer timer;
  int counter = 0;

  void tick(_) {
    counter++;
    streamController.add(counter); // 使用add 发送一个数据
    if (counter == maxCount) {
      timer.cancel();
      streamController.close(); // 关闭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');
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335