Dart基础「Flutter」

[TOC]

Dart基础

  • 在Dart中,所有能够使用变量引用的都是对象object,每个对象都是一个类class的实例。数字、函数和null都是对象,所有对象继承自Object类,为初始化的变量默认值是null
  • Dart是强类型语言,但是类型声明是可选的,Dart可以推断类型,无类型则要用dynamic类型。
  • Dart支持泛型(generic types),如List<int>(整数列表)、list<dynamic>(任意类型列表)。
  • Dart支持顶层函数(main()),以及(as well as)与类绑定的函数(分别为:静态和实例化方法),函数可嵌套。
  • Dart支持顶层变量,以及与类绑定的(静态和实例)变量,实例变量也成为fields或properties;
  • Dart没有public protected private,可以在标识前加下划线(_)表示私有。
  • 标识可以以字母或下划线(_)开始,后面可以是任意字母、下划线、数字的组合
  • Dart支持表达式expressions(have runtime value,可返回值)和语句statements(no runtime value),比如表达式 condition?exp1:exp2会有exp1或exp2中的任一个值,而与if-else就没有runtime value,语句包含多个表达式表达式不能包含语句
  • Dart可以报告两种类型的问题:
    • warnings:可能工作不正常,但是不会阻止程序运行。
    • errors:包括编译错误和运行时错误,编译错误程序无法执行,运行时错误会在运行时发生异常(exception)

代码注释

// 单行注释
/*
 *多行注释
 */
/**
 *文档注释
 */

变量与常量

Dart定义变量有两种方式:

  • 静态类型语言常用的显示指定变量类型
  • 动态指定方式,不指定类型,由vm自动推断。但是一旦指定后就不能再更改类型,如果要更改应当用dynamic 或 Object来定义变量
    var(a way to declare a variable without specifying its type)

常量定义也是两种:finaland const
定义方法是用final或const替换变量前的 var 或 类型指定,final只能set一次,const编译期常量(隐含final),final顶层或类变量在第一次使用前初始化。

  • 一是java方法,final 变量只能赋值一次,运行时常量,运行时确定,其所赋值可以是一个变量,常用于方法。
  • 另一种是Dart方式,const定义,编译期确定,其所赋值必须是一个字面常量,static const表示静态常量
final time = new DateTime.now(); //ok
const time = new DateTime.now(); //error
const list = const[1,2,3]; //ok
const list = [1,2,3]; //error

var foo = const[]; // foo 可以修改
const bar = [];    // bar 不能修改
foo = [1,2,3]; //ok
bar = [1,2,3]; //error

// Dart2.5以后,可以用类型检查和转换,定义常量
const object i = 3; //i是整数对象
const list = [i as it]; //typecast
const map = {if(i is int)i:'int'}; //use is and collection if
const set = {if(list is List<int>)...list};

注意:

  • 实例的变量只能是final,不能是const,final instance varialbles必须在构造函数体前初始化-即在变量声明时、用构造参数初始化,或在构造函数的初始化列表(initializer list)
  • 如果在类class中声明const,需要标记为static const

Built-in types

Dart内建数据类型主要包括

  • numbers
  • strings
  • booleans
  • lists(类似arrays)
  • maps
  • runes(在strings中表述Unicode字符)
  • symbols
  • enumerattions 枚举
  1. numbers
    Dart numbers包括intdouble两种类型,其中integer类型数据长度不大于64bits,数值从-2^63 to 2^63.double为64bit浮点数据。intdouble都是num的子类型(subtype),支持基本的+ - * /等操作,在int class中定义了 >> << & |等操作符,其他常用操作在dart:math library
//整数定义
var x = 1;
var hex = 0xDEA6;
//浮点定义
var y = 1.1;
var z = 1.42e5;
double z = 1; // 自动转换等同于 double z = 1.0; ver2.1以后

基础工具bsic utilites

parse() //string -> number
toString() //number -> string
toStringAsFixed() //小数位数
toStringAsPrecision() //精度
  1. Strings
//1.由单双引号创建
var s1 = 'hello';
var s2 = "hello";

//2.多行-三单/双引号
var s3 = ''' 第一行
第二行
''';
//3.原始显示不转义字符串
var s4=r'c:\windows\system32';

//4.拼接字符串
var s = 'hello' + 'world';
var name = 'mike'
var astr = 'hello $name';
var astr2 = 'hello ${name.toUpperCase()}'
// $variableName 或 ${expression}
//5. 比较字符串内容
print('hello' == 'world');
  1. booleans
    只有false 和 true两个值,不赋值则为null

  2. lsits
    更详细

列表与数组等同,下标从0开始

//1. create
var list1 = [1,2,3]; //infer推论list1 has type List<int>
print(lsit1[0]);
print(list1.length);
list.add(4);
//2. 扩展 扩展操作符spread operator(...)非空判断扩展null-aware spread operator(...?)
var list2 = [7,8,...list1]; //7,8,1,2,3
var list2 = [7,8,...?list1]; //如果list1为null也不会出错,最终返回[7,8]
//3. collection if / for
var list3 = [
'home',
if(true)'Outlet'];

var list4 = [
'home'
for(var i in lsit1)'add$i'
];

//4. create a list's a compile-time constant
var constantList = const [1,2,3]; 
constantList[1] = 1 ; //error
  1. Sets
    唯一item的无序集合。
var hal = {'ab','cd','1'} // infer hal has the type Set<String>
var hal = <String>{};
Set<String> hal = {};
var hal = {}; //会创建一个map,而不是set
hal.add('x');  // addAll()、length
final constantSet = const {'1','2' } 
// 支持 ... 和 ...?扩展,与list类似

  1. maps
    映射又称为关联数组(关联keys 和 valuse),相当于java中的HashMap,keys 和 valuses能是任意类型的对象object。key只能出现一次,valuse可以重复。
// 字面创建
var gits = {
  'first': '1',
  'second': '2'
}; // gits has type Map<String,String>

// 构造函数创建
var mp1 = new Map(); // var mp1 = Map(); 在Dart中鼓励不用new
mp1['first'] = '1';
mp1['second'] = '2';
print(mp1.length);
print(mp1['first']); //如果不存在返回null

//常量
final mp = const {1:'a',2:'b'};  //const 可省略

常用函数

length
keys
values
containsKey
containsValue
remove
forEach
map.values.toList()
  1. 枚举类型
    枚举类型称为enumerattions或enums,代表固定数量的常量特殊类型。
enum Color{
  red,
  green,
  blue  
}

assert(Color.red.index == 0) ; //枚举类型中每个值都有一个index getter方法,返回index从0开始。
//获取所有值,用values
List<Color> colors = color.values;

函数

dart中,函数(方法)也是对象,类型是Function,可以赋值给变量,也可以作为其他函数的参数。可以像调用函数一样调用一个类的实例。
定义函数

String greet(String name){
  return 'hello $name';
} //类型string 可省略 effective dart不建议

函数类型:函数类型是可选的,可以省略显示类型(建议显示指定),
返回值:void修饰时函数时无返回值,未指定时返回null。

=>操作符
函数中只有一条表达式时候可以
String greet(String name)=>“hello $name”·; =>expr 是简写了{return expr;}注意只有一条表达式expression可用此操作符,而不是一条语句statement(如if-else)
可选参数利用可选参数可实现类似重载(dart中没有重载)
可选参数可以是命名参数 或是 位置参数,函数定义可选参数只能用其中一种。

  • 命名参数:调用时用ParaName:value指明命名的参数。定义时候用{param1,param2 ..}指定命名参数,对于可选参数可以注释为@required要求调用时必须提供参数。
void enableFlags({int bold, int hidden}){ ... }
void Scrollbar({Key key, @required Widget child}){ ... }
  • 位置可选参数:用方括号[ ]包裹
String say(String from, String msg, [String device]){
  var result = '$from say $msg';
  if(device != null){
     result = '$result with a $device';
   }
}

默认值可以用=定义命名或位置参数默认值,默认值要是编译期常量(compile-constants),如果没有定义那么缺省值为null

void enableFlags({bool bold = false,bool hidden = false}){ ... }
void doStuff({List<int> lst=const[1,2,3],Mpa<int,String>gifts = const{1:'1',2:'2'}}
{...}

主函数main()
主函数是程序的入口,有一个可选参数List<String>,无返回值
void main(List<String> arguments) { ... }
函数作为参数传递

//传递给函数
void printElement(int element){print(element);} //void printElement(int element)=>print(element)  ?????
var list = [1,2,3];
list.forEach(printElement);
//传递给变量 使用了匿名函数
var loudify = (msg) => "message is:$msg";
print(loudify('hello'));

匿名函数anonymous functions
可以像lambda和closure一样使用匿名函数,与命名的函数类似,可以没有或有多个参数:

([Type] param1[,...]){ codeBlock  }

var lst = ['1','2','3'];
lst.forEach((item){
        print('${lst.indexOf(item)}is:$item')
        }); //lst.forEach((item)=>print('${lst.indexOf(item)}is:$item'));

闭包 lexical closures
闭包是一个函数对象function object,可以在原始范围外访问内部变量。并可以持久记住其状态。

Function makeAdder(num addBy){
   return (num i)=>addBy+i; // 返回一个函数对象,addBy会被返回的函数记住状态
}
void main(){
  var add2 = makeAdder(2);
  var add3 = makeAdder(3);
  
  add2(5); //7
  add3(5); //8

//==========
a() {
  int count = 0;
  printCount(){
    print($count++);
  }
  return printCount();
}
void main(){
  f = a();
  for (i=0;i<=5;i++){
    f();
  } // output:0 1 2 3 4 5
}

}

操作符

  • 比较操作符 == != > < >= <=
  • 算术运算符 + - -exp(负号) * / ~/(整除) %(余数modulo) ++ --
  • 类型测试符 as(typecast)、 is 、is!(not is)
  • 赋值操作符 = 、??= b??=a //assign value to b if b is null;otherwise b stays the same
  • 复合赋值= -= /= %= >>= ^= += *= ~/= <<= &= |= a op= b 即 a=a op b
  • 逻辑运算 !expr(not) ||(or) &&(and)
  • 位操作符 & | ^ ~ << >>
  • 条件表达式 condition ? expr1 : expr2 // if condition is true reuslt expr1 else reult expr2 ; expr1 ?? expr2 //if expr1 is not null result expr1 else result expr2
  • 级联符号 .. 允许在一个对象上执行一些列操作:
 querySelector('#confirm') //get an object
   ..text = 'Confirm'
   ..classes.add('importand')
   ..onClick.listen((e)=>window.alert('Confirmed'));
 //等同于da
 var btn = querySelector('#confirm'); //get an object
 btn.text = 'Confirm'
 btn.classes.add('importand')
 btn.onClick.listen((e)=>window.alert('Confirmed'));

//可以嵌套
final addressBook = (AddressBookBuilder()
      ..name = 'mike'
      ..email = 'x@xxx.com'
      ..phone = (phoneBuilder()
            ..number = '1234556'
            ..lable = 'home')
            .build()) //phoneBuilder().build()
       .build(); //addressBookBuiler().bulild()
  • 其他操作符
( ) 函数调用
[ ] 列表访问
.   成员访问 foo.bar
?.  条件成员访问 foo?.bar foo非空时访问foo.bar

流程控制语句

  • if-else
  • for loops
  • while and do-while
  • brak and continue
  • switch and case
  • assert
if (isRaining){
  you.bringRainCoat();
} else if (isSnowing()){
  you.wearJacket();
} else {
  car.putTopDown();
}

var callbacks = [];
for (var i=0; i<=2; i++){
  callbacks.add(()=>print(i));
}
  callbacks.forEach((c)=>c());

while(!isDone()){
  doSomething();
}

do{
  dosomethine();
}while(!isDone());

var command = 'OPEN';
switch(command){
  case 'CLOSED':
    executeClosed();
    break; //break如果缺少了会报错
  case 'OTHER':
    executeOther();
    continue now; //跳转到now标签
  case 'OPEN':
    executeOpen();
    break;
  now: // a label name
  case 'NOW_CLOSED': //empty case ok
  default:
    executeUnknown();
}
// for 循环
for (int i=0;i<=100;i++){
   ;
}

for (String item in aList){
   ;
}

int i=0;
while(i<10){
  ;
}

do {
  ;
}while(i<=10)

//assert(condition, opionalMessage)
//在开发中,使用assert语句,当条件false中断,显示默认错误提示或指定错误提示
assert(number<100);
assert(urlString.startsWith('https'),'shold start with "https".');


#### Exceptions ####
未预见到的错误发生如果没有捕捉处理,出现例外的isolate线程会挂起suspend,一般线程和其程序会终止。
throw exception `throw FormatException('Excepted')`,可以抛出任意对象 `throw 'Out of'`
```dart
try{ breedMorelamas();
}on outOfLlamasException{... } // 指定例外值
 on Exception catch(e){  // 捕捉exception
 print('Unknown exception $e');
} 
 catch(e) {... } //不指定类型,捕捉所有异常

try { }
cathch(e) { }
finally { }

Class

Dart是有类class和混合继承(mixin-based inheritance)的面向对象的编程语言,所有对象object都是一个类的实例,所有类派生自Object类,基于混合继承意味着尽管每个类都只有一个超类(superclass)一个类主体可以在多个类继承中重用,Extension methods能在不改变类和创建子类的情况下添加功能。

  • 引用类成员
    引用类成员 p.y = 3; p?.y=4 //if p is not-null set its y=4
  • 使用构造函数
    类的构造函数可以是ClassName或者ClassName.identifier
var p1 = Point(1,2);
var p1 = Point.fromJson({'x':1.'y':2});
//获取类型
print(p.runtimeType);
  • 类的变量 instance variables
    未初始化的变量为null,所有实例变量都有隐含的 gettersetter(final instance除外)。
    在声明变量时初始化,变量值会在创建实例时设置,早于构造函数和初始化列表执行。
  • 构造函数
    构造函数是与类同名的函数(可以加上标识符,可以是ClassName或者ClassName.identifier
    Dart构造函数有四种格式:
className() //普通构造函数
className.identifier() // 命名构造函数
const className() //常量构造函数  
factory className() //工厂构造函数
class Point{
  num x, y;
  point(num x,num y){
    this.x = x;
    this.y = y;
  } // 此种赋值类构造函数更好的方法是用模板 point(this.x, this.y);
}

如果没有声明构造函数,类会提供缺省的构造函数,缺省构造函数没有参数直接调用超类的无参数构造函数。
子类不会继承超类的构造函数,子类不声明构造函数仅有一个缺省的无参数无名称的构造函数。
命名构造函数使用命名构造函数可以为类实现多个构造函数,或使功能更清晰。

class Point{
  num x, y;
  pont(this.x,this.y);
  //named constructor
  point.origin(){
    this.x = 0;
    this.y = 0;
  } //原点构造函数;
}

注意由于构造函数不会继承,因此命名的构造函数在子类中没有,需要重新构建。
构造函数的执行顺序initializer list -> superclass's no-arg constructor -> main class's no-arg constructor.
如果超类没有unnamed no-argument的构造函数,必须手工调用一个构造函数,方式为subclassConstructor : supclassConstructor.identifer

  • 初始化列表 initializer list
Pont.fromJson(Map<string,num> json)
    : x = json['x'],
      y = json['y'],
      distance = sqrt(x*x+y*y){
    print('body runing');
}

  • 重定向构造函数
    使用现有构造函数可以解决问题
class Point{
  num x,y;
  point(this.x,this.y);
  pont.alongXAxis(num x):point(x,0);
}
  • Factory constructor
    使用factory关键字声明构造函数不只是返回新实例,可以返回缓存的实例,工厂函数不能使用this。工厂函数就是可以批量产生对象的函数,可以返回一个实例,而不用类的方法。
class Logger{
  final String name;
  bool mute = false;
  
  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);}
}

main(){
  var logger = Logger('UI'); //new
  var logger1 = Logger('Button');//new
  var logger3 = Logger('UI');//return cache = logger
}

如果类创建的对象不变,可以在编译期创建这个常量实例,并使用常量构造函数,确保所成员都是final

class p{
  final num x,y;
  const p(this.x,this.y); 
}
  • 方法 Method
    gettersetter所有实例变成员量都有隐含的 gettersetter(final instance除外)。但是也可以通过setget关键字来声明相应的方法,执行自定义操作
class Rectangle{
  num left,top,width,height;
  Rectangle(this.left,this.top,this.width,this.height);
  num get right=>left + width;
  set right(num value)=>left = value - width;
}

抽象方法方法可以是抽象方法,定义一个接口让其他类去实现,抽象方法只能存在于抽象类中。
抽象类不能被实例化,一般用来定义接口声明,如果要实例化抽象类,要使用工厂构造函数。

abstract class Doer{
  void doSomething(); //创建抽象方法,用;代替方法体
}

class EffectiveDoer extends Doer{
  void doSomething(){ ... }
}

隐式接口在Dart中,类和接口是统一的,每个类都隐式定义一个接口,其中包含该类成员(变量、方法)及所有声明的接口,如果想创建一个支持B类API的A类,则A类应该实现B接口。类通过在implements字句中声明一个或多个接口,然后提供接口所需的API来实现一个或多个接口。
如果有一个类A,想让类B拥有A的API,但又不想有用A中的实现,那么可以把A当作接口,用类B来implements 类A。class就是interface 当类被当作interface的时候,类中的方法就是接口的方法,需要在子类中重新实现,在子类实现的时候用@override,成员变量也要重新实现,用@override,实现接口可以有多个
如果是复用已有类的实现,使用继承extends,如果只是使用已有类的外在行为,使用接口implements

继承是单继承 ,构造函数不能继承;子类重写超类的方法 用@override; 子类调用超类的方法用super。

class Person{
  final _name; // 在接口中,但仅本库可见
  Person(this._name); //不在接口中,是构造函数
  String greet(String who)=>'Hello,$who. I am $_name.'; //在接口中
}

//person接口的实现
class Impostor implements person{ 
  get _name=>'';
  String greet(String who)=>'Hi $who.Do you know who am i?';
}

String greetBob(Person person)=>person.greet('Bob');
void main(){
  print(greetBob(Person('Mike'));
  print(greetBob(Impostor());
}
  • 接口
    不管是抽象类还是实例类都可以用来实现接口,建议使用抽象类来实现接口,因为实现 实现类里的方法和属性,如果不使用抽象类,显得乱。
    接口一般用来定义统一的操作规范。比如定义一个数据库的操作类,操作方法都一样 包括 add save delete;
    接口实现类包括操作mysql mssql mongodb等
abstract class DB{
  String uri;
  add(String data);
  save();
  delete();
}

class Mysql implements DB{
  @override // 覆盖父类实例方法。
  String uri
  Mysql(this.uri);
  @override
  add(data){ ...}
  @override
  delete(){...}
  @override
  save(){ ... }
  
  remove(){ .. } //新增的
}
  • Mixin
    多个类层次重用代码,用法为class AB extends P with A,B,会组合一个新类顺序为PAB。是一种线性化的,创建实例var ab = AB(),则ab is p ,ab is A,ab is B均为true,因为每个mixin应用都创建一个新类,还会创建一个接口,新类中扩展了超类并包含mixin类成员的副本,也实现了mixin类的接口。
    P-PA-PAB-->ab; 创建mixin类,然后将代码‘混入’扩展类中。
abstract class Animal{  // 动物的通用属性
}

// 跑的动作实现
mixin Run{ 
  run(){print('run');}
}

// 飞的动作实现
mixin fly{
  fly(){print('fly');}
}

// 游的动作实现
mixin Swim{
  swim(){print('swim');}
}


void main(){
  class Bird extends Animal with Fly{}  //会飞的鸟
  calss Dog extends Animal with Run{ }   // 会跑的狗
  class Frog extends Animal with Run,Swim{ } //会跑 会游的蛙

  Bird b = Bird();
  b.fly();
  
  Frog f = Frog();
  f.run();
  f.swim();
}


  • 操作符重载
class Vector{
  final int x,y;
  Vector(this.x,this.y);
  Vector operator +(Vector V)=>Vector(x + v.x, y + v.y);
}
  • noSuchMethod()
    在代码中尝试使用不存在的方法或变量时,作为响应,可以重写noSuchMethod()
    @overrid void noSuchMethod(Invocation invocation){print(no ${invocation.memberName});}

类的方法和变量

  • 用static实现类的变量和方法。
  • 静态变量只有在使用时才被初始化,静态方法不在实例上进行操作,不必访问this。
  • 类的方法和变量只能通过类访问,不能通过实例不能访问。

泛型 Generics

一般情况下类或函数都需要确定返回的类型,有时在需要在使用时确定类型。
泛型可以更安全:尽管可以通过继承实现以上要求,但泛型在编译期会进行类型检查,而不是在运行期。
可以快速创建复杂的类型,由于在编写时没有指定类型,因此可以在使用时随意指定类型。
自动完成类型转换。没有泛型时,如果不能确定返回类型,那么就需要返回Objcect,有了泛型就可以确定具体类型。

泛型-有形参的类型,是可以被参数化的类型。通常为了类型安全(type safety)使用泛型,另外可以写出更好的代码,减少代码重复。
List<String>读作list of string

abstract class Cache<T>{
  T getByKey(String key);
  void setBykey(String key,T value);
}

//否则就要写成
// int 类
abstract class CacheInt{
  int getByKey(String key);
  void setBykey(String key,int value);
// string 类
abstract class CacheString{
  int getByKey(String key);
  void setBykey(String key,String value);
}

//泛型类型初始化使用只需要使用<Tyupe>或<keyType,valueType>即可。
var names = <String>['1','2']; //lsits
var set = <String>{'1','2'}; //sets
//如果使用构造函数初始化
var names = List<String>();
var names = Set<String>.from(names);

//泛型类
class PrintClass<T>{
  List list = new List<T>();
  void add(T value)=>this.list.add(value);
  void printInfo(){ .. }
}
//泛型方法
//泛型最初主要用于支持类,现在可以支持泛型方法。
//T 可以用在三个地方: 1 函数返回类型  2 参数类型   3 局部变量
T first<T>(List<T> ts){
  ...
  T tmp = ts[0];
  return tmp;
}

// 限定参数范围 T extends classname
T sumPair<T extends num>(List<T> items){
  return T items[0]+items[1];
}

//var ls = <double>[1.2,3.5];
//var b = sumPair(<int>[1,2]); //=3
//var c = sumPair(ls); //=4.7

库和可见性

import和库指令可以帮助创建模块化且可共享的代码库。库不仅提供API,而且是隐藏细节的方法,用_开头的标识仅库内部,可见。每个Dart程序都是一个库,即使它不使用库指令。

  • 可以使用packages分发库。
  • 使用库命名空间import 'dart:html'。dart内建库标识dart: 其他库可以使用 路径 或 package:package指定用一个包管理器作为库提供者。imprt 'package:test/test.dart'
  • 指定库前缀import 'package:lib2/lib2.dart' as lib2使用`lib2.Element el=lib2.Element()
  • 导入库的部分内容:导入show,隐藏hide例如: import 'package:lib1/lib1.dart' show foo;
  • 后期导入库deferred
  import 'package:greetings/hello.dart' deferred as hello;
  Future greet() async{
    await hello.loadLibrary(); //即使多次调用,也只会载入一次
    hello.printGreeting();
}

异步Asynchrony support

async & await
在Dart中没有子线程一说,所有代码都是在一条主线上运行,比较耗时的操作用异步来实现。
async用来修饰方法,卸载方法的括号之后,await写在方法内部,但是await 关键字必须在async函数内部使用,不然会报错,await表达式可以使用多次。即使是在main()中使用await main()也要标记async

Future main() async{
  ....0  await for(var request in requestServer){
   .....
  }
}
void main(){
  getName1();
  getName2();
  getName3();
}

getName1() async {
  await getStr1();
  await getStr2();
  print('getName1');
}

getStr1(){
  print('getStr1');
}

getStr2(){
  print('getStr2');
}

getName2(){
  print('getName2')
}

getName3(){
  print('getName3')
}

执行顺序 main - getName1 - getstr1(遇到await会先执行这一行,之后立即返回future(void)) -

执行顺序 执行结果 说明
main() 主函数执行
getName1() 第一个函数
getStr1() getStr1 遇到await会先执行这一行,之后立即返回future(void),然后将剩余方法放入事件队列(即getStr2()和print('getName1'))
getName2() getName2
getName3() getName3 主程序执行完毕
getStr2() getStr2 队列中还有未执行
print('getName1')

** then, catchError, whenComplete**
async方法遇到await会返回一个future对象,是一个未来值,完成之后才能取出。then关键字就是获取等待完成之后的返回值。

void main(){
  new future(() => futureTask())     //异步执行函数
        .then((i) => "result is $i") //任务执行后的子任务
        .then((m) => print(m))      //m为上个任务执行后的返回值 “reulst is 10”
        .then((_) => Future.error('出错了')) // 可以抛出一个异常
        .catchError(print)   //捕捉异常,然后执行代码,print
        .whenComplete(()=>print("complete")); //左右任务执行完成后 执行的回调函数
}
futureTask(){
  return 10;
}

在Dart的main isolate中只有一个Event looper,维护两个队列,即事件队列Event Queue,和Microtask Queue不断从消息队列中取出消息并处理它们,消息可以是用户输入、点击、定时器等。

同时main isolate还维护一个MicroTask Queue,对已经执行的事件,再次执行then,就会放入微队列 **main线程执行完毕,再看事件队列,执行事件队列之前需要检查 微队列中是否有东西,如果微队列中有就需要先执行 **

schedureMicrotask()可以主动将代码放入微队列中

void main(){
  testSchduleMicrotask();
}

void testSceduleMicrotask(){
  scheduleMicrotassk(()=>print('s1')); //放入微队列
  new Future.delayed(new Duration(seconds:1), ()=>print('2')); //延时直接放入事件队列最后
  new Future(()=>print('s3')).then((_){print('s4');scheduleMicrotask(()=>print('s5'));}
  print('s6')
}

主循环 s6
事件队列 s3(s4)、s2
微队列 s1、s5

  • 尽量将任务放入event事件队列中。
  • 使用Future的then方法或whenComplete方法来指定任务顺序。
  • 为了保持响应性,尽量不要将大量计算放入这两个队列。
  • 大量计算任务放入额外的isolate中(另外的线程)

生成器

yield 在迭代生成器中返回序列值中的一个值。有时候需要生成一个序列,并循环处理每个item,如果使用列表,当元素很多时候,会占用大量内存,如果用生成器每次会返回一个值,而不会返回整个列表,并记住位置,下一次返回next。因此yield 相当于生成器函数中的return。
包括

  • 同步生成器 返回 Iterable object
  • 异步生成器 返回 Stream object
//如生成斐波那契数列

Iterable<int> Fab(int max) sync*{
  int n=0;
  int a=0;
  int b=1;
  int t=0;
  while(n<max){
    yield b;
    t=a;
    a = b;
    b = t + b;
    n++;
  }
}

Stream<int> Fab(int max) async*{
  int n=0;
  int a=0;
  int b=1;
  
  while(n<max){
    yield b;
    t=a;
    a = b;
    b = t + b;
    n++;
  }
}

void main(){
  for (item in Fab(10)){
    print(item);
  }
}

//对于递归生成器,递归前用 yield *提高性能
Iterable<int> DownFrom(int n) sync* {
  if (n > 0){
    yield n;
    yield * DownFrom(n-1);
  }
}

函数类型定义

typedef目前仅用于定义函数类型

typedef Compare = int Function(Object a, Object b);
//typedef Compare<T> = sort(T a,T b);
class SortedCollection{
  Compare compare;
  SortedCollection(this.compare);
}

int sort(Object a,Object b)=>0;
//int sort(int a, int b)=>a-b;
void main(){
  SortedCollection coll = SortedCollection(sort);
  ....
}

元数据Metadata####

元数据给代码附加更多信息,元数据以@开始

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