Dart语言详解

文章目录

  • 1 变量
    • 1.1 变量-变量的声明
    • 1.2 变量-默认值
    • 1.3 变量-final和const
  • 2 内置类型
    • 2.1 内置类型-num, int, double
    • 2.2 Strings 字符串
    • 2.3 内置类型-bool
    • 2.4 内置类型-List
    • 2.5 内置类型-Map
    • 2.6 内置类型-Set
    • 2.7 内置类型-Runes
    • 2.8 内置类型-Symbol
  • 3 函数
    • 3.1 函数-定义
    • 3.2 函数-可选参数
    • 3.3 函数-匿名函数
    • 3.4 函数-闭包
    • 3.5 函数-函数别名
  • 4 操作符
  • 5 流程控制语句
  • 6 异常
    • 6.1 异常-Exception类型
    • 6.2 异常-Error类型
    • 6.3 异常-抛出
    • 6.4 异常-捕获
  • 7 类
    • 7.1 类-构造函数
    • 7.2 类-命名构造函数
    • 7.3 类-重定向构造函数
    • 7.4 类-初始化列表
    • 7.5 类-调用超类构造函数
    • 7.6 类-常量构造函数
    • 7.7 类-工厂构造函数
    • 7.8 类-Setter和Getter
    • 7.9 类-抽象类
    • 7.10 类-可调用类
  • 8 Mixin
  • 9 泛型
    • 9.1 泛型-泛型函数
    • 9.2 泛型-构造函数泛型
    • 9.3 泛型-泛型限制
    • 9.4 泛型-与java区别
  • 10 库
    • 10.1 库-使用核心库
    • 10.2 库-载入第三方库
    • 10.3 库-载入文件
    • 10.4 库-指定库前缀
    • 10.5 库-选择性载入
    • 10.6 库-延迟载入
    • 10.7 库-自定义库
  • 11 异步
    • 11.1 异步-async和await
    • 11.2 异步-then,catchError,whenComplete
    • 11.3 异步-Event-Looper
    • 11.4 异步-Event Queue和Microtask Queue
    • 11.5 异步-任务调度
    • 11.6 异步-new Future()
    • 11.7 异步-scheduleMicrotask()
  • 12 生成器
    • 12.1 生成器-同步生成器
    • 12.2 生成器-异步生成器
    • 12.3 生成器-递归生成器
  • 13 隔离-Isolates
  • 14 元数据(注解)
    • 14.1 元数据(注解)-@deprecated
    • 14.2 元数据(注解)-@override
    • 14.3 元数据(注解)-自定义
  • 15 注释
    • 15.1 注释-单行注释
    • 15.2 注释-多行注释
    • 15.3 注释-文档注释

1 变量

1.1 变量-变量的声明

var
dynamic
Object

dynamic和Object区别:

新建一个“1-variables.dart”,添加如下代码:

void main(){
  dynamic d1 = "1234";
  Object o1 = "1234";
  d1.test();
  o1.test();
}

d1.test();不会报错
o1.test();会报错
说明dynamic编译时不会检查,Object在编译时会检查。

总结如下:

  //var声明一个初始化的变量,变量的类型不能再改变
  var variable1 =
      'hongxue'; //变量是一个引用。名字为 name 的变量引用了 一个内容为 “hongxue” 的 String 对象。
      //variable1 = 123;//变量初始化后,name变量的类型被推断为String类型,其类型不能再改变

  //dynamic和Object声明的变量初始化后,变量的类型仍可改变
  dynamic variable2 = 'hongxue';
  variable2 = 123;
  //  variable2.test();//调用不存在的test()方法,编译通过,运行报异常。编译阶段不检查类型
  Object variable3 = 'hongxue';
  variable3 = 123;
   //  variable3.test();//调用不存在的test()方法,编译不通过。编译阶段检查类型

  //使用确定类型显示声明变量,变量的类型不能再改变
  String name3;
  name3 = 'hongxue';
//  name3 = 123;//变量的类型不能再改变

//var:如果没有初始值,可以变成任何类型
//dynamic:动态任意类型,编译阶段不检查类型
//Object:动态任意类型,编译阶段检查检查类型
//区别:
//唯一区别 var 如果有初始值,类型被锁定
  • var:如果没有初始值,可以变成任何类型
  • dynamic:动态任意类型,编译阶段不检查类型
  • Object:动态任意类型,编译阶段检查检查类型

区别:

  • 唯一区别 var 如果有初始值,类型被锁定

1.2 变量-默认值

没有初始化的变量自动获取一个默认值为null
一切皆对象,对象的默认值为null

  //没有初始化的变量默认值都是null。一切皆对象,对象的默认值是null
  bool isEmpty;
  assert(isEmpty == null);

1.3 变量-final和const

共同点:

  1. 声明的类型可省略
  2. 初始化后不能再赋值
  3. 不能和var同时使用
  //1.  被final或者const修饰的变量,变量类型可以省略
  final fVariable1 = 'hongxue';
//  final String fVariable1 = 'hongxue';
  const cVariable1 = 'hongxue';
//  const String cVariable1 = 'hongxue';

  //2.  被 final 或 const 修饰的变量无法再去修改其值。
//   fVariable1 = 'damon';
//   cVariable1 = 'damon';

  //3.  final或const不能和var同时使用。
//  final var fVariable1 = 'hongxue';
//  const var fVariable1 = 'hongxue';

区别(需要注意的地方):

  1. 类级别常量,使用static const
  2. const可使用其他const 常量的值来初始化其值
  3. 使用const赋值声明,const可省略
  4. 可以更改非final、非const变量的值,即使曾经具有const值
  5. const导致的不可变性是可传递的
  6. 相同的const常量不会在内存中重复创建
  7. const需要是编译时常量
  //4.  如果是类级别常量,使用static const
  DateTime; //可参照DateTime static const int monday = 1;

  //5.  const可以使用其他 const常量的值来初始化其值
  const width = 100;
  const height = 100;
  const square = width * height;

  //6.  const赋值 申明可省略
  const List clist = [1, 2, 3];
//  const List clist = const [1, 2, 3];//dart 2之前,const赋值必须用const声明

  //7.  可以更改非final,非const变量的值,即使它曾经具有const值
  var varList = const [1, 2, 3];
  final finalList = const [1, 2, 3];
  const constList = [1, 2, 3];
  varList = [1];
//  constList = [1];
//  finalList = [1];

  //8.  const导致的不可变性是可传递的
  final List ls = [1, 2, 3];
  ls[1] = 4;
  print(ls);
  const List ls1 = [1, 2, 3];
//  ls1[1] = 4;

  //9. 相同的const常量不会在内存中重复创建
  final finalList1 = [1, 2];
  final finalList2 = [1, 2];
  print(identical(finalList1, finalList2)); //identical用于检查两个引用是否指向同一个对象

  const constList1 = [1, 2];
  const constList2 = [1, 2];
  print(identical(constList1, constList2)); //identical用于检查两个引用是否指向同一个对象

  //10. const 需要是编译时常量
  final DateTime finalDateTime = DateTime.now();
  //  const DateTime constDateTime = DateTime.now();//DateTime.now() 是运行期计算出来的值


2 内置类型

  1. Numbers 数值
  2. Strings 字符串
  3. Booleans 布尔值
  4. Lists 列表(数组)
  5. Sets 集合
  6. Maps 集合
  7. Runes 符号字符
  8. Symbols 标识符

2.1 内置类型-num, int, double

int和double是num的子类

  • int : 整数值
  • double : 64-bit双精度浮点数
  /// ---------------------------------Numbers数值:num, int, double--------------------------------
  print('-----------------------Numbers------------------------');
  int i = 1; //整数值
  double d = 1.0; //double  64-bit (双精度) 浮点数
  int bitLength = i.bitLength;
  print('bitLength: ${bitLength}'); //bitLength判断int值需要多少bit位
  double maxFinite = double.maxFinite;
  print('maxFinite: ${maxFinite}'); //maxFinitedouble的最大值
  //int和double都是num的子类
  num n1 = 1;
  num n2 = 1.0;
  //支持十进制、十六进制
  int i1 = 0xfff;
  //科学计数法
  double d1 = 1.2e2; //120.0
  //转换
  //String->int
  int i2 = int.parse('1');
  double d2 = 1; //当double的值为int值时,int自动转成double
  print('d2: ${d2}');
//  int i2 = int.tryParse('1.0');//返回null

  //int->String
  String str = 123.toString(); //数字也是对象
  print('-----------------------Numbers------------------------');

2.2 Strings 字符串

  • Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串

  • 可以使用三个单引号或者双引号创建多行字符串对象

  • 可以使用 r 前缀创建”原始raw”字符串。

  • 可以在字符串中使用表达式: ${expression},如果表达式是一个标识符,可以省略 {},如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串

 /// ---------------------------------Strings字符串:String--------------------------------
  print('-----------------------Strings------------------------');
  //Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串
  var name = 'xiaoming';
  //可以在字符串中使用表达式: ${expression},如果表达式是一个标识符,可以省略 {}。 如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串
  var names = 'hongxue ${name}';
  var rawNames = r'hongxue ${name}'; //r 前缀可以创建一个 “原始 raw” 字符串
  print('names: ${names}');
  print('rawNames: ${rawNames}');
  //如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串。
//  print(Map);
  //可以使用三个单引号或者双引号也可以 创建多行字符串对象
  var multiLinesString = '''
  hongxue
  xiaoming''';
  print('multiLinesString: ${multiLinesString}');

  //StringBuffer
  var sb = StringBuffer(); //dart 2 可以省略new
  sb..write('aaa')..write('bbb')..write('ccc'); //..级联符实现链式调用
  sb.writeAll(['ddd', 'eee', 'fff'], ','); //第二个参数表示分隔符,将第一个参数列表里的数据用这个分隔符拼接起来
  print('sb: ${sb}');
  print('-----------------------Strings------------------------');

2.3 内置类型-bool

  • bool对象未初始化的默认值是null
 /// ---------------------------------Booleans布尔值:bool--------------------------------
  print('-----------------------Booleans------------------------');
  //bool :true 和false
  bool isNull;
  print('isNull: ${isNull}');
  print('-----------------------Booleans------------------------');

2.4 内置类型-List

  • Dart中可以直接打印list包括list的元素,List也是对象。java中直接打印list结果是地址值
  • Dart中List的下标索引和java一样从0开始
  • 和java一样支持泛型。
  • 有增删改查,支持倒序,自带排序、洗牌,可使用+将两个List合并
 /// ---------------------------------Lists列表(数组):List--------------------------------
  print('-----------------------Lists------------------------');
  //声明
  //自动长度
  List growableList = List();
//  List growableList = new List()..length = 3;
  growableList..add(1)..add(2)..add('xiaoming');
  print('growableList: ${growableList}');
  //固定长度
  var list = List(3); //List的声明,可以用var也可用List。
  list[0] = 1; //下标索引从0开始
  list[1] = 2;
  list[2] = 'xiaoming';
  print('list: ${list}');
  //元素类型固定
  var typeList = List();
  typeList.add(1);
  typeList.add(2);
  typeList.add(3);
  print('typeList: ${typeList}');
  //常用属性
  int first = typeList.first;
  print('typeList.first: ${first}'); //第一个元素
  int last = typeList.last;
  print('typeList.last: ${last}'); //最后一个元素
  int length = typeList.length;
  print('typeList.length: ${length}'); //元素个数
  bool isEmpty = typeList.isEmpty;
  print('typeList.isEmpty: ${isEmpty}'); //是否为空
  bool isNotEmpty = typeList.isNotEmpty;
  print('typeList.isNotEmpty: ${isNotEmpty}'); //是否不为空
  Iterable reversed = typeList.reversed;
  print('typeList.reversed: ${reversed}'); //倒序
  //常用方法 增删改查,排序,洗牌,复制子列表
  var list4 = [];
  //增
  list4.add(1);
  print('add 1 :${list4}');
  list4.addAll([2, 3, 4]);
  print('addAll [2, 3, 4] :${list4}');
  list4.insert(0, 0);
  print('insert(0, 0) :${list4}');
  list4.insertAll(1, [5, 6, 7]);
  print('insertAll(1, [5, 6, 7]) :${list4}');
  //删
  list4.remove(5);
  print('remove 5 :${list4}');
  list4.removeAt(2);
  print('remove at 0 :${list4}');
  //改
  list4[4] = 5;
  print('update list4[4] to 5 :$list4}');
  //range
  list4.fillRange(0, 3, 9);
  print('fillRange update list4[0]-list4[2] to 9 :$list4}');
  Iterable getRange = list4.getRange(0, 3);
  print('getRange list4[0]-list4[2] :$getRange}');
  //查
  var contains = list4.contains(5);
  print('list4 contains 5 :${contains}');
  var indexOf = list4.indexOf(1);
  print('list4 indexOf 1 :${indexOf}');
  int indexWhere = list4.indexWhere((test) => test == 5);
  print('list4 indexWhere 5 :${indexWhere}');
  //排序
  list4.sort();
  print('list4 sort :${list4}');
  //洗牌
  list4.shuffle();
  print('list4 shuffle :${list4}');
  //复制子列表
  var list5 = list4.sublist(1);
  print('sublist(1) list5 :${list5}');
  //操作符
  var list6 = [8, 9];
  print('list6 :${list6}');
  var list7 = list5 + list6;
  print('list5 + list6 :${list7}');
  print('-----------------------Lists------------------------');

2.5 内置类型-Map

  • 跟java类似
 /// ---------------------------------Maps键值对集合:Map--------------------------------
  print('-----------------------Maps------------------------');
  //声明
  //动态类型
  var dynamicMap = Map();
  dynamicMap['name'] = 'hongxue';
  dynamicMap[1] = 'android';
  print('dynamicMap :${dynamicMap}');
  //强类型
  var map = Map();
  map[1] = 'android';
  map[2] = 'flutter';
  print('map :${map}');
  //也可以这样声明
  var map1 = {'name': 'hongxue', 1: 'android'};
  map1.addAll({'name':'xiaoming'});
  print('map1 :${map1}');
  //常用属性
//  print(map.isEmpty); //是否为空
//  print(map.isNotEmpty); //是否不为空
//  print(map.length); //键值对个数
//  print(map.keys); //key 集合
//  print(map.values); //value集合

  //常用方法 增删改查
  print('-----------------------Maps------------------------');

2.6 内置类型-Set

  • set1.difference(set2):返回set1集合里有但set2里没有的元素集合
  • set1.intersection(set2):返回set1和set2的交集
  • set1.union(set2):返回set1和set2的并集
  • set1.retainAll():set1只保留某些元素(要保留的元素要在原set中存在)
/// ---------------------------------Sets集合:Set--------------------------------
  print('-----------------------Sets------------------------');
  //6.  Set无重复列表
  var dynamicSet = Set();
  dynamicSet.add('hongxue');
  dynamicSet.add('flutter');
  dynamicSet.add(1);
  dynamicSet.add(1);
  print('dynamicSet :${dynamicSet}');
  //常用属性与list类似

  //常用方法 增删改查与list类似
  var set1 = {'hongxue', 'flutter'};
  print('set1 :${set1}');
  var set2 = {'hongxue', 'xiaoming', 'dart'};
  print('set2 :${set2}');
  var difference12 = set1.difference(set2);
  var difference21 = set2.difference(set1);
  print('set1 difference set2 :${difference12}'); //返回set1集合里有但set2里没有的元素集合
  print('set2 difference set1 :${difference21}'); //返回set2集合里有但set1里没有的元素集合
  var intersection = set1.intersection(set2);
  print('set1 set2交集 :${intersection}'); //返回set1和set2的交集
  var union = set1.union(set2);
  print('set1 set2并集 :${union}'); //返回set1和set2的并集
  set2.retainAll(['hongxue', 'flutter']); //只保留(要保留的元素要在原set中存在)
  print('set2只保留hongxue flutter :${set2}');
  print('-----------------------Sets------------------------');

2.7 内置类型-Runes

Main(){
  Runes runes = new Runes('\u{1f605} \u6211‘);
  var str1 = String.fromCharCodes(runes);  
  print(str1);
}
  /// ---------------------------------Runes符号字符--------------------------------
  //Runes用于在字符串中表示Unicode字符 https://copychar.cc/emoji/
  String runesStr = '?';
  print(runesStr);
  print(runesStr.length); //表示占 2 个 16 位字符
  print(runesStr.runes.length); //表示占 1 个 32 位字符

  Runes runes = new Runes('\u{1f605} \u6211');
  var str1 = String.fromCharCodes(runes); //使用String.fromCharCodes显示字符图形
  print(str1);
  String str2 = '\u{1f605} \u6211'; //如果非4个数值,需要把编码值放到大括号中
  print(str2);

2.8 内置类型-Symbol

  • Symbol标识符,主要是反射用,现在mirrors模块已经被移除

3 函数

3.1 函数-定义

  • 可在函数内定义
  • 定义函数时可省略类型
  • 支持缩写语法 =>
  //普通函数定义
  int add(int x, int y) {
    return x + y;
  }
  print(add(1, 2));

  //所有的函数都返回一个值。如果没有指定返回值,则 默认把语句 return null; 作为函数的最后一个语句执行。
  testFunc() {}
  ;
  print(testFunc());

  //可省略类型(不建议)
  add1(x, y) {
    return x + y;
  }

  print(add1('1', '2'));
  print(add1(1, 2));

  //箭头函数:=>表达式
  int add2(int x, int y) => x + y;

3.2 函数-可选参数

  • 可选命名参数
  • 可选位置参数
  • 默认参数值
  print('---------------------------可选参数 begin---------------------------');

  //可选命名参数:使用 {param1, param2, …} 的形式来指定命名参数
  int add3({int x, int y, int z}) {
    x ??= 1;
    y ??= 2;
    z ??= 3;
    return x + y + z;
  }

  print(add3());//打印 6

  //可选位置参数:把可选参数放到 [] 中,必填参数要放在可选参数前面
  int add4(int x, [int y, int z]) {
    y ??= 2;
    z ??= 3;
    return x + y + z;
  }

  print(add4(1));//打印 6

  //可选命名参数默认值(默认值必须是编译时常量),目前可以使用等号'='或冒号':'
  //Dart SDK 1.21 之前只能用冒号,冒号的支持以后会移除,所以建议使用等号
  int add5(int x, {int y = 2, int z = 3}) {
    return x + y + z;
  }

  //前面的必填参数没有名字
  print(add5(1, y: 10, z: 2));

  //可选位置参数默认值(默认值必须是编译时常量),只能使用等号'='
  int add6(int x, [int y = 2, int z = 3]) {
    return x + y + z;
  }

  print(add6(1));

  //使用list或map作为默认值,但必须是const
  void func(
      {List list = const [1, 2, 3],
      Map map = const {1: 1, 'name': 'hongxue'}}) {
  }

  print('---------------------------可选参数 end---------------------------');

打印:

---------------------------可选参数 begin---------------------------
6
6
13
6
---------------------------可选参数 end---------------------------

3.3 函数-匿名函数

  • 可赋值给变量,通过变量调用
  • 可在其他函数中直接调用或传递给其他函数
print('---------------------------匿名函数 begin---------------------------');

  //匿名函数
  //赋值给变量
  //无参匿名函数
  var anonFunc1 = () => print('无参匿名函数');
  anonFunc1();

  //有参匿名函数
  var anonFunc = (name) => 'I am $name';
  print(anonFunc('xiaoming'));

  //通过()调用,不推荐
//  (()=>print('不推荐'))();

  //匿名函数传参
  List test(List list, String func(str)) {
    for (var i = 0; i < list.length; i++) {
      list[i] = func(list[i]);
    }
    return list;
  }

  var list = ['x', 'i', 'a', 'o', 'm'];
  print(test(list, (str) => str * 2)); //String * int, Dart和Python可以这样用

  //List.forEach()就用的匿名函数
  List list1 = [11, 12, 13];
  list1.forEach((item) => print('$item'));

  print('---------------------------匿名函数 end---------------------------');

打印如下:

---------------------------匿名函数 begin---------------------------
无参匿名函数
I am xiaoming
[xx, ii, aa, oo, mm]
11
12
13
---------------------------匿名函数 end---------------------------

3.4 函数-闭包

  //返回Function对象(闭包)
  Function makeAddFunc(int x) {
    x++;
    return (int y) => x + y;
  }

  var addFunc = makeAddFunc(2);
  print(addFunc(3));

打印:6

3.5 函数-函数别名

//函数别名
typedef MyFunc(int a, int b);

//根据MyFunc相同的函数签名定义两个函数
subtsract(int a, int b) {
  print('subtsract: ${a - b}');
}

divide(int a, int b) {
  print('divide: ${a / b}');
}

//typedef 也可以作为参数传递给函数
calculator(int a, int b, MyFunc func) {
  func(a, b);
}
void main(){

 // 函数别名
  MyFunc myFunc;
  //可以指向任何同签名的函数
  myFunc = subtsract;
  myFunc(5, 2);
  myFunc = divide;
  myFunc(8, 2);
  //typedef 作为参数传递给函数
  calculator(5, 2, subtsract);
  calculator(8, 2, divide);

}

打印:

subtsract: 3
divide: 4.0
subtsract: 3
divide: 4.0

4 操作符

Dart语言详解_第1张图片

main() {
  //Operators 操作符
  /// ---------------------------------后缀操作符 ?.--------------------------------
  //  条件成员访问 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员
  String a;
  print(a?.length);

  /// ---------------------------------取商操作符 ~/--------------------------------
  //  被除数 ÷ 除数 = 商 ... 余数,A ~/ B = C,这个C就是商。相当于Java里的 /
  print(2 / 3);
  print(2 ~/ 3);

  /// ---------------------------------类型判定操作符--------------------------------
  //类型判定操作符:as、is、is!在运行时判定对象类型
  //as 类型转换
  num iNum = 1;
  num dNum = 1.0;
  int i = iNum as int;
  double d = dNum as double;
  print([i, d]);

//  String s = iNum as String;

  //is 如果对象是指定的类型返回 True
  print(iNum is int);
  Child child;
  Child child1 = new Child();
  print(child is Parent); //child is Null
  print(child1 is Parent);

  //is! 如果对象是指定的类型返回 False
  print(iNum is! int);

  /// ---------------------------------条件表达式--------------------------------
  // 三目运算符 condition ? expr1 : expr2
  bool isFinish = true;
  String txtVal = isFinish ? 'yes' : 'no';
  // expr1 ?? expr2,如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果。
  bool isPaused;
  isPaused = isPaused ?? false;
  //或者
  isPaused ??= false;

  /// ---------------------------------级联操作符--------------------------------
  // .. 可以在同一个对象上 连续调用多个函数以及访问成员变量。
  // 严格来说, 两个点的级联语法不是一个操作符。 只是一个 Dart 特殊语法。
  StringBuffer sb = new StringBuffer();
  sb
    ..write('hongxue')
    ..write('flutter')
    ..write('\n')
    ..writeln('xiaoming');

  //重写操作符

}

class Parent {}

class Child extends Parent {}

打印:

null
0.6666666666666666
0
[1, 1.0]
true
false
true
false

重载操作符:

void main(){
  final v1 = Vector(5,6);
  final v2 = Vector(2,2);
  final r1 = v1 + v2;
  final r2 = v1 - v2;
  print([r1.x,r1.y]);
  print([r2.x,r2.y]);
}

//重载操作符
class Vector{
  final int x;
  final int y;

  const Vector(this.x,this.y);

  //重载+
  Vector operator +(Vector v){
    return new Vector(x + v.x, y + v.y);
  }
  //重载
  Vector operator -(Vector v){
    return new Vector(x - v.x, y - v.y);
  }

}

打印:

[7, 8]
[3, 4]

5 流程控制语句

  • if else
  • for, forEach, for-in
  • while , do-while
  • break , continue
  • switch case
main() {
  var collection = [0, 1, 2];
  //forEach
  collection.forEach((item) => print('forEach: $item'));
  //for-in遍历元素
  for (var item in collection) {
    print('for-in: $item');
  }
}

打印:

forEach: 0
forEach: 1
forEach: 2
for-in: 0
for-in: 1
for-in: 2

6 异常

6.1 异常-Exception类型

在这里插入图片描述


6.2 异常-Error类型

在这里插入图片描述

6.3 异常-抛出

// 抛出Exception 对象
// throw new FormatException(‘格式异常');

// 抛出Error 对象
// throw new OutOfMemoryError();

// 抛出任意非null对象
// throw '这是一个异常';

6.4 异常-捕获

try {
  throw new OutOfMemoryError();
} on OutOfMemoryError {
  print('没有内存了');
} on Error catch(e) {
  print('Unknown error: $e');
} catch (e, s) {
  print('Exception details: $e');
  print('Stack Trace: $s');
} finally {
  print('end');
} 

打印:

没有内存了
end

7 类

7.1 类-构造函数

//java中写法
class Point {
  double x;
  double y;

  Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
}
//dart建议写法
class Point {
  num x;
  num y;
  Point(this.x, this.y);
}
main() {
  //普通构造函数
  var p = new Point(1, 1); //new 可省略 var point = Point(1, 2);
  print(p);
}

打印:

Point(x = 1, y = 1)

7.2 类-命名构造函数

class Point { 
  num x; 
  num y; 

  Point(this.x, this.y); 

  //命名构造函数
  Point.fromJson(Map json) { 
    x = json['x']; 
    y = json['y']; 
  } 
}
void main(){
	//命名构造函数
	p = Point.fromJson({'x': 2, 'y': 2});
	print(p);
}

打印:

Point(x = 2, y = 2)

7.3 类-重定向构造函数

class Point { 
  num x; 
  num y; 

  Point(this.x, this.y); 

  //重定向构造函数,使用冒号调用其他构造函数
  Point.alongXAxis(num x) : this(x, 0);
}
  //重定向构造函数
  p = Point.alongXAxis(0);
  print(p);

打印:

Point(x = 0, y = 0)

7.4 类-初始化列表

import 'dart:math';

class Point {
  //final变量不能被修改,必须被构造函数初始化
  final num x;
  final num y;
  final num distanceFromOrigin;

  //初始化列表
  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

7.5 类-调用超类构造函数

class Parent {
  int x;
  int y;

  //父类命名构造函数不会传递  
  Parent.fromJson(x, y)
      : x = x,
        y = y {
    print('父类命名构造函数');
  }
}
class Child extends Parent {
  int x;
  int y;
  //若超类没有默认构造函数, 需要手动调用超类其他构造函数
  Child(x, y) : super.fromJson(x, y) {
    //调用父类构造函数的参数无法访问 this
    print('子类构造函数');
  }

  //在构造函数的初始化列表中使用super(),需要把它放到最后
  Child.fromJson(x, y) 
	 : x = x,
	   y = y,
	   super.fromJson(x, y) {
    print('子类命名构造函数');
  }
}
main() {
  //调用超类构造函数
  var child = Child.fromJson(1, 2);
  var child1 = Child(3, 4);
}

打印:

超类命名构造函数
子类命名构造函数
超类命名构造函数
子类构造函数

7.6 类-常量构造函数

class Point2 {
  //定义const构造函数要确保所有实例变量都是final
  final num x;
  final num y;
  static final Point2 origin = const Point2(0, 0);

  //const关键字放在构造函数名称之前,且不能有函数体
  const Point2(this.x, this.y);
}
void main(){
	//常量构造函数
  var p2 = const Point2(4, 4);
  print(p2);
  var p21 = Point2(4, 4); //创建的是非 常量对象
  var p22 = const Point2(4, 4);
  print(identical(p2, p21));
  print(identical(p2, p22));
}

打印:

Point2(x = 4, y = 4)
false
true

7.7 类-工厂构造函数

class Singleton {
  String name;
  //工厂构造函数无法访问this,所以这里要用static
  static Singleton _cache; 

  //工厂方法构造函数,关键字factory
  factory Singleton([String name = 'singleton']) =>
      Singleton._cache ??= Singleton._newObject(name);

  //定义一个命名构造函数用来生产实例
  Singleton._newObject(this.name);
}

打印:true

7.8 类-Setter和Getter

main() {
  //set get
  var rect = new Rectangle(1, 1, 10, 10);
  print(rect.left);
  rect.right = 15;
  print(rect.left);
}

//setter getter
//每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter
//可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter
class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  // getter 和 setter 的好处是,可以开始使用实例变量,后面可以把实例变量用函数包裹起来,而调用你代码的地方不需要修改。
  //获取right值
  num get right => left + width;
  //设置right值,同时left也发生变化
  set right(num value) => left = value - width;
  //获取bottom值
  num get bottom => top + height;
  //设置bottom值,同时top也发生变化
  set bottom(num value) => top = value - height;
}

打印:

1
5

7.9 类-抽象类

  • abstract关键字修饰class
  • 继承的方式使用
  • 接口的方式使用

工厂模式两种方式:

1 创建工厂构造函数

main() {
  //创建工厂构造函数
  var footMassage = new Massage('foot');
  footMassage.doMassage();
  var bodyMassage = new Massage('body');
  bodyMassage.doMassage();
  var specialMassage = new Massage('%#@##@##');
  specialMassage.doMassage();
}
//工厂模式
abstract class Massage {
  factory Massage(String type) {
    switch (type) {
      case 'foot':
        return new FootMassage();
      case 'body':
        return new BodyMassage();
      default:
        return new SpecialMassage();
    }
  }
  void doMassage();
}

class FootMassage implements Massage {
  @override
  doMassage() {
    print('脚底');
  }
}
class BodyMassage implements Massage {
  @override
  void doMassage() {
    print('全身');
  }
}
class SpecialMassage implements Massage {
  @override
  void doMassage() {
    print('特殊');
  }
}

打印:

脚底
全身
特殊

2 创建顶级函数

main() {
  //创建顶级函数
  var footMassage = massageFactory('foot');
  footMassage.doMassage();
  var bodyMassage = massageFactory('body');
  bodyMassage.doMassage();
  var specialMassage = massageFactory('xxx');
  specialMassage.doMassage();
}
//工厂函数
class Massage {
  void doMassage(){
    print('按摩');
  }
}
class FootMassage extends Massage {
  @override
  doMassage() {
    print('脚底');
  }
}

class BodyMassage extends Massage {
  @override
  void doMassage() {
    print('全身');
  }
}

class SpecialMassage extends Massage {
  @override
  void doMassage() {
    print('特殊');
  }
}
Massage massageFactory(String type){
  switch (type) {
    case 'foot':
      return new FootMassage();
    case 'body':
      return new BodyMassage();
    default:
      return new SpecialMassage();
  }
}

打印:

脚底
全身
特殊

7.10 类-可调用类

main() {
  //可调用类
  var cf = new ClassFunction();
  var out = cf("hongxue","flutter,","xiaoming");
  print('$out'); // Hi there, gang!
  print(cf.runtimeType); // WannabeFunction
  print(out.runtimeType); // String
  print(cf is Function); // true
}
//可调用类
class ClassFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

打印:

hongxue flutter, xiaoming!
ClassFunction
String
false

8 Mixin

可以理解为多进程。
Dart语言详解_第2张图片

main() {
  Bicycle().transport();
  Motorcycle().transport();
  Car().transport();
  WoodenCar().transport();  //四轮木制脚踏车
}

//交通工具类,拥有运输功能
abstract class Transportation {
  //运输功能
  void transport();
}

//自行车
class Bicycle extends Transportation
    with TwoWheelTransportation, LowSafetyIndex, BodyEnergyTransportation {
  @override
  void transport() {
    print(
        "自行车:\n动力组件: ${powerUnit()} , 安全指数: ${safetyIndex()} , 动力来源:${energy()}");
  }

//  String safetyIndex() => "low";
//
//  String powerUnit() => "两个轮子";
//
//  String energy() => "全靠腿登";
}

//摩托车
class Motorcycle extends Transportation
    with TwoWheelTransportation, LowSafetyIndex, GasolineEnergyTransportation {
  @override
  void transport() {
    print(
        "摩托车:\n动力组件: ${powerUnit()} , 安全指数: ${safetyIndex()} , 动力来源:${energy()}");
  }

//  String safetyIndex() => "low";
//
//  String powerUnit() => "两个轮子";
//
//  String energy() => "汽油";
}

//汽车
class Car extends Transportation
    with
        FourWheelTransportation,
        MiddleSafetyIndex,
        GasolineEnergyTransportation {
  @override
  void transport() {
    print(
        "汽车:\n动力组件: ${powerUnit()} , 安全指数: ${safetyIndex()} , 动力来源:${energy()}");
  }

//  String safetyIndex() => "middle";
//
//  String powerUnit() => "四个轮子";
//
//  String energy() => "汽油";
}

//双轮交通工具
class TwoWheelTransportation {
  String powerUnit() => "两个轮子";
}

//四轮交通工具,一般来说安全性能为中
class FourWheelTransportation {
  String powerUnit() => "四个轮子";
}

//安全指数中等的交通工具儿
class MiddleSafetyIndex {
  String safetyIndex() => "middle";
}

//安全指数低的交通工具儿
class LowSafetyIndex {
  String safetyIndex() => "low";
}

//人力发动机
class BodyEnergyTransportation {
  String energy() => "全靠腿登";
}

//汽油能源交通工具
class GasolineEnergyTransportation {
  String energy() => "汽油";
}

//四轮木制脚踏车
class WoodenCar extends Car
//    with LowSafetyIndex, BodyEnergyTransportation
//implements LowSafetyIndex, BodyEnergyTransportation
    {
  @override
  void transport() {
    print(
        "四轮木制脚踏车:\n动力组件: ${powerUnit()} , 安全指数: ${safetyIndex()} , 动力来源:${energy()}");
  }
}

打印:

自行车:
动力组件: 两个轮子 , 安全指数: low , 动力来源:全靠腿登
摩托车:
动力组件: 两个轮子 , 安全指数: low , 动力来源:汽油
汽车:
动力组件: 四个轮子 , 安全指数: middle , 动力来源:汽油
四轮木制脚踏车:
动力组件: 四个轮子 , 安全指数: middle , 动力来源:汽油

顺序问题:

void main(){
  var messageAB = AB().getMessage();
  print(messageAB);
  var messageBA = BA().getMessage();
  print(messageBA);
  var messageC = C().getMessage();
  print(messageC);
  var messageCC = CC().getMessage();
  print(messageCC);
}

//顺序问题
//如果2个或多个超类拥有相同签名的A方法,那么子类会以继承的最后一个超类中的A方法为准。
//当然这是子类没有重写A方法的前提下,如果子类自己重写了A方法则以本身的A方法为准
class A {
  String getMessage() => 'A';
}

class B {
  String getMessage() => 'B';
}

class P {
  String getMessage() => 'P';
}

class AB extends P with A, B {}

class BA extends P with B, A {}

class C extends P with B, A {
  String getMessage() => 'C'; //优先级最高的是在具体类中的方法。
}

class CC extends P with B implements A {
} //这里的implement只是表明要实现A的方法,这个时候具体实现是再B中mixin了具体实现

打印:

B
A
C
B

9 泛型

void main(){
  //使用泛型,很多的容器对象,在创建对象时都可以定义泛型类型,跟java一样
  var list = List();
  list.add('aaa');
  list.add('bbb');
  list.add('ccc');
  print(list);

  var map = Map();
  map[1] = 'aaaa';
  map[2] = 'bbbb';
  map[3] = 'cccc';
  print(map);
}

打印:

[aaa, bbb, ccc]
{1: aaaa, 2: bbbb, 3: cccc}

9.1 泛型-泛型函数

void main(){
  var key = addCache('hongxue', 'xiaoming');
  print(key);
}

//泛型函数
K addCache(K key, V value) {
  K temp = key;
  print('${key}: ${value}');
  return temp;
}

打印:

hongxue: xiaoming
hongxue

9.2 泛型-构造函数泛型

void main(){
  //构造函数泛型
  var p = Phone('123456');
  print(p.mobileNumber);
}

//构造函数泛型
class Phone {
  final T mobileNumber;
  Phone(this.mobileNumber);
}

打印:

123456

9.3 泛型-泛型限制

void main(){
  //泛型限制, 通过 extends 关键字限定可泛型使用的类型
  var footMassage = FootMassage();
  var m = Massage(footMassage);
  m.massage.doMassage();
}
//泛型限制
class Massage {
  final T massage;
  Massage(this.massage);
}
class FootMassage {
  void doMassage() {
    print('脚底');
  }
}

打印:

脚底

9.4 泛型-与java区别

  • Java中的泛型信息是编译时的,泛型信息在运行时是不存在的
  • Dart的泛型类型是固化的,在运行时也有可以判断的具体类型
void main(){
  var names = List();
  print(names is List);//true
  print(names.runtimeType); // List
}

打印:

true
List

10 库

10.1 库-使用核心库

使用import关键字来载入库:

import "dart:math";

void main() {
  print(sqrt(4));//开平方 2.0
}

10.2 库-载入第三方库

https://pub.flutter-io.cn/

1.编写pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.0
  dio: ^2.1.0

2.调用

import "package:dio/dio.dart";

void main() {
  getHttp();
}

void getHttp() async {
  try {
    Response response = await Dio().get("https://www.baidu.com");
    print(response);
  } catch (e) {
    print(e);
  }
}

10.3 库-载入文件

新建一个mylib1.dart

class MyLib {
  String name;
  static MyLib _cache; //工厂构造函数无法访问 this。所以这里要静态的

  factory MyLib([String name = 'singleton']) =>
      MyLib._cache ??= MyLib._newObject(name);

  //定义一个命名构造函数用来生产实例
  MyLib._newObject(this.name);
}

class Test {
  void test() => print('Test');
}

test(){

}

//载入文件
import “mylib1.dart";

void main() {
  var myLib1 = MyLib();
}

10.4 库-指定库前缀

如果两个库有冲突的标识符,可以为其中一个或两个库都指定前缀:

mylib1.dart

class MyLib {
  String name;
  static MyLib _cache; //工厂构造函数无法访问 this。所以这里要静态的

  factory MyLib([String name = 'singleton']) =>
      MyLib._cache ??= MyLib._newObject(name);

//定义一个命名构造函数用来生产实例
  MyLib._newObject(this.name);
}

class Test {
  void test() => print('Test');
}

test(){

}

mylib2.dart

class MyLib{
  String name;
  static MyLib _cache; //工厂构造函数无法访问 this。所以这里要静态的

  factory MyLib([String name = 'singleton']) =>
      MyLib._cache ??= MyLib._newObject(name);

//定义一个命名构造函数用来生产实例
  MyLib._newObject(this.name);
}

class Test{
  void test() => print('Test');
}

载入文件

import 'mylib1.dart' as lib1; //载入文件
import 'mylib2.dart' as lib2; //如果两个库有冲突的标识符,可以为其中一个或两个库都指定前缀

void main() {
  var myLib = lib1.MyLib();
  var myLib2 = lib2.MyLib();
}

10.5 库-选择性载入

  • show-只载入库的某些部分
  • hide-筛选掉库的某些部分
import 'mylib1.dart' as lib1 show Test; //只载入库的某些部分
import 'mylib2.dart' as lib2 hide Test; //筛选掉库的某些部分

void main(){
  //选择性载入
  var test = lib1.Test();
  var lib = lib2.MyLib();

}

10.6 库-延迟载入

  • 使用deferred as导入
  • 使用标识符调用loadLibrary()加载库
import 'mylib1.dart' deferred as lazyLib; //延迟载入

void main(){
  //延迟载入
  lazyLoad();
}
//延迟载入
//可提高程序启动速度
//用在不常使用的功能
//用在载入时间过长的包
lazyLoad() async {
  await lazyLib.loadLibrary();
  var t = lazyLib.Test();
  t.test();
}

10.7 库-自定义库

新建util.dart

part of mylib;

void printUtil() => print('util');

新建tool.dart

part of mylib;

void printTool() => print('tool');

新建mylib.dart

library mylib;

part 'util.dart';
part 'tool.dart';

void printMyLib() => print('mylib');
import 'mylib/mylib.dart';//载入自定义库

void main(){
  //载入自定义库
  printMyLib();
  printUtil();
  printTool();
}

打印:

mylib
util
tool

11 异步

11.1 异步-async和await

import 'dart:async';

main() async {
  // async wait
  getName1();
  getName2();
  getName3();
}

// async wait
Future getName1() async {
//  getStr1();//可以不用await打断点看下await后的区别
  await getStr1(); //遇到第一个await表达式执行暂停,返回future对象,await表达式执行完成后继续执行
  await getStr2(); //await表达式可以使用多次
  print('getName1');
}

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

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

getName2() {
  print('getName2');
}

getName3() {
  print('getName3');
}

打印:

getStr1
getName2
getName3
getStr2
getName1

11.2 异步-then,catchError,whenComplete

import 'dart:async';

main() async {
  //then catchError whenComplete
  new Future(() => futureTask()) //  异步任务的函数
      .then((m) => "a:$m") //   任务执行完后的子任务
      .then((m) => print('a$m')) //  其中m为上个任务执行完后的返回的结果
      .then((_) => new Future.error('error'))
      .then((m) => print('damon'))
      .whenComplete(() => print('whenComplete1')) //不是最后执行whenComplete,通常放到最后回调

//      .catchError((e) => print(e))//如果不写test默认实现一个返回true的test方法
      .catchError((e) => print('catchError:' + e), test: (Object o) {
    print('test:' + o);
    return true; //返回true,会被catchError捕获
//        return false; //返回false,继续抛出错误,会被下一个catchError捕获
  })
      .catchError((e) => print('catchError2:' + e))
//      .then((m) => print('dongnao'))
//      .whenComplete(() => print('finish'))
      ;
}

int futureTask() {
//  throw 'error';
  return 10;
}

11.3 异步-Event-Looper

Dart语言详解_第3张图片

打印:

aa:10
whenComplete1
test:error
catchError:error

11.4 异步-Event Queue和Microtask Queue

Dart语言详解_第4张图片

11.5 异步-任务调度

  • 使用Future类,可以将任务加入到Event Queue的队尾
  • 使用scheduleMicrotask函数,将任务加入到Microtask Queue队尾
    Dart语言详解_第5张图片

11.6 异步-new Future()

import 'dart:async';

main() async {
  // Future
  testFuture();
}

//Future
void testFuture() {
  Future f = new Future(() => print("f1"));
  Future f1 = new Future(() => null); //7163524
//  Future f1 = new Future.delayed(Duration(seconds: 1) ,() => null);//7132465
  Future f2 = new Future(() => null);
  Future f3 = new Future(() => null);

  f3.then((_) => print("f2"));
  f2.then((_) {
    print("f3");
    new Future(() => print("f4"));
    f1.then((_) {
      print("f5");
    });
  });

  f1.then((m) {
    print("f6");
  });
  print("f7");
}

打印:

f7
f1
f6
f3
f5
f2
f4

11.7 异步-scheduleMicrotask()

import 'dart:async';

main() async {
  //scheduleMicrotask
  testScheduleMicrotask();
}
//scheduleMicrotask
void testScheduleMicrotask() {
  //918346572
  scheduleMicrotask(() => print('s1'));

  new Future.delayed(new Duration(seconds: 1), () => print('s2'));

  new Future(() => print('s3')).then((_) {
    print('s4');
    scheduleMicrotask(() => print('s5'));
  }).then((_) => print('s6'));

  new Future(() => print('s10'))
      .then((_) => new Future(() => print('s11')))
      .then((_) => print('s12'));

  new Future(() => print('s7'));

  scheduleMicrotask(() => print('s8'));

  print('s9');
}

打印:

s9
s1
s8
s3
s4
s6
s5
s10
s7
s11
s12
s2

Dart语言详解_第6张图片

顺序图


12 生成器

12.1 生成器-同步生成器

void main(){
  //同步生成器
  //调用getSyncGenerator立即返回Iterable
  var it = getSyncGenerator(5).iterator;
  //  调用moveNext方法时getSyncGenerator才开始执行
  while (it.moveNext()) {
    print(it.current);
  }
}

//同步生成器: 使用sync*,返回的是Iterable对象
Iterable getSyncGenerator(int n) sync* {
  print('start');
  int k = n;
  while (k > 0) {
    //yield会返回moveNext为true,并等待 moveNext 指令
    yield k--;
  }
  print('end');
}

打印:

start
5
4
3
2
1
end

12.2 生成器-异步生成器

1:

void main(){
  //异步生成器
  //调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行
  //getAsyncGenerator(5).listen((value) => print(value));
  StreamSubscription subscription = getAsyncGenerator(5).listen(null);
  subscription.onData((value) {
    print(value);
  });
}

//异步生成器: 使用async*,返回的是Stream对象
Stream getAsyncGenerator(int n) async* {
  print('start');
  int k = 0;
  while (k < n) {
    //yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制
    yield k++;
  }
  print('end');
}

打印:

start
0
1
2
3
4
end

2 :

import 'dart:async';

void main(){
  //异步生成器
  //调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行
  StreamSubscription subscription = getAsyncGenerator(5).listen(null);
  subscription.onData((value) {
    print(value);
    if (value >= 2) {
      subscription.pause(); //可以使用StreamSubscription对象对数据流进行控制
    }
  });
}

//异步生成器: 使用async*,返回的是Stream对象
Stream getAsyncGenerator(int n) async* {
  print('start');
  int k = 0;
  while (k < n) {
    //yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制
    yield k++;
  }
  print('end');
}

打印:

start
0
1
2

12.3 生成器-递归生成器

import 'dart:async';

void main(){
  //递归生成器
  //同步
  var it1 = getSyncRecursiveGenerator(5).iterator;
  while (it1.moveNext()) {
    print(it1.current);
  }
  //异步
  getAsyncRecursiveGenerator(5).listen((value) => print(value));
}

//递归生成器:使用yield*
Iterable getSyncRecursiveGenerator(int n) sync* {
  if (n > 0) {
    yield n;
    yield* getSyncRecursiveGenerator(n - 1);
  }
}

//异步递归生成器
Stream getAsyncRecursiveGenerator(int n) async* {
  if (n > 0) {
    yield n;
    yield* getAsyncRecursiveGenerator(n - 1);
  }
}

13 隔离-Isolates

  • 所有Dart代码都在隔离区内运行,而不是线程。每个隔离区都有自己的内存堆,确保不会从任何其他隔离区访问隔离区的状态。

14 元数据(注解)

14.1 元数据(注解)-@deprecated

main() {
  dynamic tv = new Television();
  tv.activate();
  tv.turnOn();
}

class Television {
  @deprecated
  void activate() {
    turnOn();
  }

  void turnOn() {
    print('Television turn on!');
  }
}

14.2 元数据(注解)-@override

main() {
  dynamic tv = new Television();
  tv.activate();
  tv.turnOn();
  tv.turnOff();
}

class Television {
  @deprecated
  void activate() {
    turnOn();
  }
  
  void turnOn() {
    print('Television turn on!');
  }
  @override
  noSuchMethod(Invocation mirror) {
    print('没有找到方法');
  }
}

14.3 元数据(注解)-自定义

//todo.dart

class Todo {
  final String who;
  final String what;

  const Todo({this.who, this.what});
}
import 'todo.dart’;

main() {
  dynamic tv = new Television();
  tv.doSomething();
}

class Television {
  @Todo(who: 'damon', what: 'create a new method')
  void doSomething() {
    print('doSomething');
  }
}

15 注释

15.1 注释-单行注释

单行注释以//开头。Dart编译器会忽略//和行尾之间的所有内容。

// 这是单行注释

15.2 注释-多行注释

  • 多行注释以/开头,以/结尾。介于/*和 */两者之间的内容会被编译器忽略(除非该注释是一个文档注释)。
  • 多行注释可以嵌套。
/*
 * 这是多行注释
 * 这是多行注释 
 */

15.3 注释-文档注释

  • 文档注释以///或者/**开头。
  • 可以通过dartdoc命令导出文档。
/// 这是文档注释

/**
  * 这是文档注释
  */

你可能感兴趣的:(07,Flutter,flutter,dart,混合开发)