Dart语言学习笔记

2020-05-13  本文已影响0人  Simon_z

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');
  }
}
上一篇下一篇

猜你喜欢

热点阅读