Skip to content

简介

官方文档 dart.cn

环境搭建

下载 SDK

js
https://dart.cn/get-dart/archive // 下载完毕后解压到指定目录

配置环境变量

js
// 依次打开 我的电脑右键=>属性=>高级系统设置=>环境变量=>双击Path=>粘贴 SDK bin存放路径=>依次点击确定

打开命令行窗口输入 dart --version 如能显示版本则表示安装成功

安装 vscode 插件

运行第一个程序

新建 holle.dart 文件并打开终端运行

dart
// 程序的入口:main 函数
void main() {
  // 打印字符串
  print('holle');
}

基础语法

变量

使用 var 定义一个变量

dart
// 变量默认值是 null
// 变量的值不会进行隐式转换
void main() {
  // 定义变量,变量支持类型推断
  var a = 1;
  a = 2;
  // a='ddd' 报错
  print(a);
}

常量

定义常量使用 const 和 final

dart
void main() {
  const a = 1;
  final b = 2;
  const f = 3;
  // a=2; 报错,常量不可修改
  // b=3; 报错,常量不可修改
  var c = 1;
  var d = 2;
  // const res = a + b; 报错 const 定义的常量是编译期常量,值是在编译时赋值
  const res2 = a + f; // 如果都是编译期常量可以赋值给 const
  final res3 = a + b; // 不报错,final 定义的常量是运行时常量,值是在运行时赋值
  print(res2); // 4
  print(res3); // 3
  const time = DateTime.now();// 报错,无法将运行时的值分配给 const 常量
  final time2 = DateTime.now();// 成功,可以将运行时的值分配给 final 常量
}

枚举

dart
// 通过 enum 声明枚举,它是数量固定的常量值
enum Color { red, green, blue }

void main() {
  // 访问枚举某个值的索引
  print(Color.green.index); // 1
  // 访问枚举整个列表
  print(Color.values); // [Color.red, Color.green, Color.blue]
}

数据类型

dart 中分为如下 5 中常用数据类型

dart
// num (数值)	bool(布尔) String(字符串) List(列表) Map(字典)

数值

dart
void main() {
  num n = 2; // num 用来定义整数或浮点数
  n = 2.3;
  int n2 = 3; // int 用来定义整数
  // n2 = 3.3; // 报错,int 不能用来定义浮点数
  double n3 = 4.4; // double 用来定义浮点数
  n3 = 4;// 如果 double 赋值一个整数,实际上还是转成了浮点数保存
  print(n3); // 4.0
  // 常用 api
  n3.toString(); // 类型转换
  n3.abs(); // 绝对值
  n3.toStringAsFixed(4); // 保留 4 位小数

  num n = 0 / 0;
  print(n); // NaN
  print(n.isNaN); // true
}

布尔值

dart
void main() {
  bool a = true;
  a = false;
}

字符串

dart
void main() {
  String str = 'holle';
  print(str);
  // 字符串拼接
  double price = 199.0;
  String res = '${price}元';
  // 可写成 '$变量' 或 '${表达式}'
  print(res); // 199.0元
  String s = """
  三个引号可以换行
  """;

  // api
  print("str".split(''));// [s, t, r] 和 js 中 split 方法一致
  print('str'.replaceAll('s', '')); // tr     和 js中替换字符串api一致
  // 支持正则替换
  print('s2t3r44'.replaceAll(RegExp(r'\d+'), '')); // str
  print('erf'.contains('e'));// true
  print('erf'.indexOf('e')); // 0

  // String.split     	   字符串切割成列表
  // String.replaceAll     字符串替换
  // String.contains       字符串查找,检测字符串是否包含某个字符
  // String.indexOf        找出某个字符出现的索引
}

列表

dart
void main() {
  List arr = [1, '2', 3];
  print(arr.length); // 列表长度
  print(arr[2]); // 查询列表某一项
  arr[2] = '3'; // 修改
  print(arr);
  arr.add('3'); // 在列表末尾添加一个元素
  print(arr);
  arr.addAll(['t', 'y']); // 在列表末尾添加多个元素
  print(arr); // [1, 2, 4, value, t, y]
  arr.remove('3'); // 根据元素名删除(删除一个),这里是删除字符串类型的3
  print(arr);
  arr.removeAt(0); // 根据索引删除元素
  print(arr);
  // 列表遍历
  arr.forEach((element) {
    print(element);// 打印列表的每一项
  });

  List a = [1, 2, 3];
  List a2 = [...a, 4, 5, 6];
  Map o = {'a': 2};
  Map o2 = {...o, 'k': 4}; // 展开运算符和js中使用类似
  print(a2); // [1, 2, 3, 4, 5, 6]
  print(o2); // {a: 2, k: 4}
  var l3 = new List.empty(
      growable: true); // 创建列表,当 empty 方法参数 growable 为true时表示创建一个可以改变长度的列表
  l3.add(1);
  print(l3); // [1]
  var l4 = new List.filled(3, 6);
  print(l4); // [6, 6, 6]
  List a = [1, 2, 3];
  var l;
  print([...?l, ...a]); // [1, 2, 3]
  print([2, 3, 4].reversed); // (4, 3, 2)
  print([2, 3, 4].reversed.toList()); // [4, 3, 2]
  List a = [1, 2, 3];
  a.insert(1, 4);
  a.insertAll(1, [5, 6]);
  print(a);
  print(['123', '456'].join('-')); //123-456
  var a = [1, 2, 3].map((e) {
    return e * e;
  });
  print(a); //(1, 4, 9)
  print([1, 2, 3].where((element) {
    return element <= 2;
  })); //(1, 2)
  print([1, 2, 3].any((element) {
    return element <= 2;
  })); //true
  print([1, 2, 3].every((element) {
    return element <= 2;
  })); //false
  var a = [[1],[2]];
  var a2 = a.expand((element) => element);
  print(a2); // (1,2)
  print([1, 2, 3].fold<num>(2, (p, element) => p * element)); // 12
}
// List.add  		在列表末尾添加一个元素
// List.addAll 		在列表末尾添加多个元素
// List.remove 		根据元素名删除(删除一个)
// List.removeAt 	根据索引删除元素
// List.forEach 	列表遍历
// new List.empty   创建列表的一种方式,当参数为true时表示创建的列表可以改变长度(可以添加元素)
// new List.filled  创建列表的一种方式,参数一表示创建列表的长度,参数二表示要填充的元素
// [...a]		    和js展开运算符类似,还可以展开字典
// [...?a]			当a不能被展开时不会执行展开操作避免报错
// List.reversed    列表翻转,反转后不是列表
// List.reversed.toList()    将reversed反转后的数据转化为列表
// List.insert      在列表指定索引插入元素
// List.insertAll   在列表指定索引插入多个元素
// List.join		将数组拼接成字符串,和 js 中使用类似
// List.map			遍历列表对列表进行一些操作并返回一个由括号包裹的可迭代数据,需要转换为列表
// List.where		遍历列表返回符合条件的可迭代数据,需要转化为列表
// List.any		    查找该列表是否有符合条件的元素,返回一个布尔值
// List.every		查找该列表里的元素是否全符合条件,返回一个布尔值
// List.expand		列表降维默认只能将二维转化成一维
// List.fold		和 js 中 reduce 相似

字典

dart
void main() {
  Map obj = {'a': 2, 'b': 3};
  const j = 'a';
  // 查
  // 也可以写成 obj['a']
  print(obj[j]); // 2
  // 查字典长度
  print({'a': 1, 'b': 2}.length); // 2
  // 改
  obj['a'] = 3;
  // 增
  obj['c'] = 4;
  // 删
  obj.remove('a');
  // 遍历
  obj.forEach((key, value) {
    print('键$key$value');
  });
  print(obj);
  print({'a': 1}.containsValue(1));//true
  print({'a': 1, 'b': 2}.keys); //(a, b)
  print({'a': 1, 'b': 2}.values); //(1, 2)
  Map a = {'a': 1, 'b': 2};
  a.removeWhere((key, value) => key == 'a');
  print(a); //{b: 2}
}
// Map.containsValue		检测字典中是否含有某个值
// Map.keys					列举字典中所有的键
// Map.values				列举字典中所有的值
// Map.removeWhere			遍历字典根据条件删除对应元素

Set

dart
// Set 是一个无序的,元素唯一的集合
void main() {
  // 字面量方式创建 Set
  var s = <int>{1, 2, 3};
  // 构造函数创建
  var fr = new Set();
  fr.add('1');
  fr.add('2');
  fr.addAll([3, 4]);
  print(fr); // {1, 2, 3, 4}
  print([1, 2, 2, 3].toSet().toList()); // [1, 2, 3] 利用Set给列表去重
  // 求交集
  print({1, 2, 3, 4}.intersection({1, 2, 5, 6})); // {1, 2}
  // 求并集
  print({1, 2, 3, 4}.union({1, 2, 5, 6})); // {1, 2, 3, 4, 5, 6}
  // 求差集
  print({1, 2, 3, 4}.difference({1, 2, 5, 6})); // {3, 4}
  // 返回第一个
  print({1, 2, 3, 4}.first); // 1
  // 返回最后一个
  print({1, 2, 3, 4}.last); // 4
  // 集合不能通过下标取值
  print({1, 2, 3, 4}[1]); // 报错
}

dynamic

dart
// dynamic 可以保存任意类型的数据,编码灵活
void main() {
  // 使用 dynamic 声明的变量会关闭编译器的类型检查
  dynamic a = 20;
  a = '30';
  print(a); // 也是可以正常使用的
}

其他数据类型

基本使用

安全机制

dart
void main() {
  String str2 = 'lol';
  print(str2.length); // 3
  String str;
  print(str.length); // 报错
  // 解决
  // 使用 ? 明确指定的变量可以为空
  String? str3;
  // 表示非空检查,如果 str3 为空则不会调用属性或方法
  print(str3?.length);
}

运算符

算术运算符

dart
void main() {
  int n1 = 10;
  int n2 = 3;
  print(n1 + n2); // 13 加
  print(n1 - n2); // 7 减
  print(n1 * n2); // 30 乘
  print(n1 / n2); // 3.3333333333333335 除
  print(n1 ~/ n2); // 3 取整:取除法结果的整数部分
  print(n1 % n2); // 1 取余
  // print(n1++); // 10 自增
  // print(n2--); // 3 自减
  print(++n1); // 11 自增
  print(--n2); // 2 自减
}

赋值运算符

dart
void main() {
  int n1 = 10;
  double n2 = 10;
  // print(n1 += 1); // 11 加等于
  // print(n1 -= 1); // 9 减等于
  // print(n1 *= 2); // 20 乘等于
  print(n2 /= 2); // 5.0 只有 double 类型数据才能进行除等于运算
}

比较运算符

dart
void main() {
  int n1 = 10;
  int n2 = 20;
  print(n1 > n2); // false 大于
  print(n1 < n2); // true 小于
  print(n1 >= n2); // false 大于等于
  print(n1 == n2); // false 等于
  print(n1 != n2); // true 不等于
}

逻辑运算符

dart
void main() {
  int n1 = 0;
  int n2 = 5;
  print(n1 > 28 && n2 > 4); // false 一假即假
  print(n1 > 28 || n2 > 4); // true 一真即真
  print(!(n1 > 28 || n2 > 4)); // false 取反
}

地板除

dart
// 地板除是先进行除法再将结果向下取整
print(7 ~/ 4); // 1

类型判断运算符

dart
// is 表示左边的类型是否是右边的类型
print([1, 2] is List); // true
// !is 表示上面写法取反
print([1, 2] is! List); // false

避空运算符

dart
// 表示如果左边为空则取右边的值,和或运算符类似
print(null ?? 3); // 3

// 另一种用法
var a;
// if (a == null) {
//   a = 3;
// }
// 上面注释的代码可用避空运算符实现
a ??= 3;

条件属性运算符

dart
// 保护为空的属性,当不存在某一属性时不会去访问防止报错
var obj;
print(obj?.length); // null

级联运算符

dart
// myobj.myMethod();返回的是 myMethod 方法的返回值
// myobj..myMethod();返回的是 myobj 对象的引用
Set s = new Set();
// s.add(1);
// s.add(2);
// s.remove(2);
// 下面写法利用级联运算符可实现上面一样的操作
s..add(1)..add(2)..remove(2);
print(s);

函数

dart
// void 表示该函数无返回值(默认返回null),函数也有自己的类型是 Function
void main() {
  print(sum(2, 3));
}

// 返回两数之和的函数,sum 也可以写在 main 函数体内,不过必须写在调用之前
int sum(int a, int b) {
  return a + b;
}

// 借助类型推断可以简写为如下形式,此时参数的类型是 dynamic 动态类型,什么类型都能接收
sum( a,  b) {
  return a + b;
}

// 定义可选参数和给可选参数指定默认值,这种写法在调用的时候需要以键值对的方式传入
sum(int a , int b,{int? c,String? d='2'}) {
  print(a + b);
}
// 这种写法在调用的时候需要以键值对的方式传入,这里的 c、d参数需要如下写法传入
sum(1, 2,c:2,d:'3');

// 可选参数的另一种写法,这种写法表示 c 可选且默认值是 0
sum(int a, int b, [int c = 0]) {
    print(a + b);
}
sum(1, 2,3);

箭头函数

dart
// 箭头函数的函数体里只能有一条语句
// 箭头函数仅仅只是普通函数的简写方式不同于 js 里的箭头函数有其他的作用
void main() {
  print(sum(2, 3));
}

sum(int a , int b) {
  return a+b;
}

// 上面函数可简写为如下箭头函数形式
sum(int a , int b) => a+b;

立即执行函数

dart
((int n) {
    print(n);
})(17); // 17

作用域

dart 中的作用域和 js 中一致

闭包

dart 中闭包和 js 中一致

类名构造函数

dart
// 使用 class 关键字声明一个类,所有的类都是继承自 Object 类
void main() {
  // 使用
  Person p = Person('张三', 22);
  print(p.age);
  print(p.jiao());
}

// 定义类
class Person {
  // Person(){
  //   print('默认构造函数无参数默认隐藏');
  // }
  // 只能有一个与类同名的构造函数
  // Person(String name, int age) {
  //   this.name = name;
  //   this.age = age;
  //   print('自定义类名构造函数有参数');
  // }
  // 自定义类名构造函数时,如果函数的参数和类的属性同名即可简写。如上面写法可简写为如下写法
  Person(this.name, this.age);

  String name = '小名';
  num? age;
  String jiao() {
    return '${this.age}${this.name}';
  }
}

命名构造函数

dart
void main() {
  // 使用命名构造函数
  Person p = Person.withName('张三');
  print(p.age);
  print(p.jiao());
}

class Person {
  Person(this.name, this.age);
  // 命名构造函数可以有多个
  // Person.withName(String name){
  //   this.name = name;
  // }
  // 上面可简写为如下格式
  Person.withName(this.name);
  String name = '小名';
  num? age;
  String jiao() {
    return '${this.age}${this.name}';
  }
}

常量构造函数

dart
// 如果类生成的对象不会改变,可以通过常量构造函数使这些对象成为编译时常量,可以提高性能
class Point {
  num x;
  Point(this.x);
}

class ImmutablePoint {
  // 属性必须通过 final 声明
  final x;
  // 常量构造函数必须通过 const 声明,且不能有函数体
  const ImmutablePoint(this.x);
}

void main() {
  // 创建实例对象时 new 关键字可以省略不写
  var p1 = new Point(1);
  var p2 = new Point(1);
  print(p1 == p2); // false

  // 声明不可变对象必须通过 const
  var p3 = const ImmutablePoint(1);
  var p4 = const ImmutablePoint(1);
  print(p3 == p4); // true

  // 常量构造函数可以当做普通构造函数使用
  var p5 = new ImmutablePoint(1);
  var p6 = new ImmutablePoint(1);
  print(p5 == p6); // false
}

工厂构造函数

dart
// 不会直接创建对象,而是在构造函数内部通过代码来决定要创建的对象
void main() {
  // 使用工厂构造函数创建对象
  Person p = Person.withInfo('张晓', 19);
  print(p.age);
  print(p.jiao());
}

class Person {
  Person(this.name, this.age);
  Person.withName(this.name, this.age);
  // 工厂构造函数必须返回一个对象,可以是之前定义的类名构造函数
  factory Person.withInfo(String name, int age) {
    // 工厂函数内不能访问 this
    // 工厂函数不能被实例化
    // return Person.withName(name, age);
    return age < 0 ? Person.withName(name, 0) : Person.withName(name, age);
  }
  String name = '小名';
  num? age;
  String jiao() {
    return '${this.age}${this.name}';
  }
}

class Person {
  String name = '';
  static dynamic instance = null;
  // 工厂构造函数主要是用来避免多次实例化重复实例化出来多个对象,提高性能
  factory Person([String name = '刘宝']) {
    // 工厂构造函数内不能访问 this 如果想访问类中属性必须用 类.属性 访问
    // 工厂构造函数不能被实例化
    if (Person.instance == null) {
      Person.instance = new Person.newSelf(name);
    }
    return Person.instance;
  }
  // 命名构造函数
  Person.newSelf(this.name);
}

void main() {
  Person p = new Person('小米');
  print(p.name); // 小米
  Person p2 = new Person('小米2');
  print(p2.name); // 小米
}

私有属性和方法

test.dart

dart
// 只有把类单独抽离出去私有属性和方法才起作用,写在一个文件中不起作用
class Dog {
  // 公有属性
  String name = '小名';
  // 私有属性 在名称前加上 _ 表示私有,私有属性只能在本类中使用
  int _age = 20;
  // 公有方法
  void jiao() {
    print('jiao');
  }

  // 私有方法
  void _run() {
    print('jiao');
  }
}

holle.dart

dart
// 导入其他文件
import 'test.dart';

void main() {
  Dog dog = Dog();
  dog.name = '大黄';
  dog.jiao();
  // dog.run(); 报错,无法访问私有属性或方法
}

getter 和 setter

dart
class Circle {
  final double PI = 3.14;
  num r;
  Circle(this.r);
  // 使用 get 声明的方法不能有小括号
  num get area {
    return this.PI * this.r * this.r;
  }

  set setR(value) {
    this.r = value;
  }
}

void main() {
  Circle c = new Circle(2);
  print(c.area); // 12.56
  c.setR = 3;
  print(c.area); // 28.259999999999998
}

初始化列表和重定向构造函数

dart
class Rect {
  int height;
  int width;
  // Rect([int height = 2, int width = 2]) {
  //   this.height = height;
  //   this.width = width;
  //   print('${this.height} -- ${this.width}');
  // }
  // 初始化列表,上面的构造函数赋默认值写法可简写为如下代码
  Rect()
      : height = 4,
        width = 5 {
    print('${this.height} -- ${this.width}');
  }
}

void main() {
  Rect c = new Rect();
}
////////////////////////////////////////////////////

class Point {
  double x, y, z;
  Point(this.x, this.y, this.z);
  // 初始化列表特殊用法(重定向构造函数)
  // 这里表示如果值传递两个参数,就用 Point 构造函数去初始化值,这里的 this 代表类本身
  Point.towD(double x, double y) : this(x, y, 0);
}

void main() {
  Point c = new Point.towD(1, 2);
}

static

dart
// 通过 static 来声明静态成员,静态成员可以通过类名称直接访问(不需要实例化)
// 实例化是比较消耗性能的,声明静态成员可以提高程序性能
class Person {
  static String name = '张三';
  int age = 2;
  printInfo() {
    // print(this.name); 不能通过 this 访问静态属性或方法
    // print(age);静态方法中不能访问非静态属性
    print(name);
  }

  printInfo2() {
    // 非静态方法可以访问静态属性
    print(name);
  }
}

void main() {
  print(Person.name); // 静态成员可以直接通过类名访问
  // print(Person.printInfo2);  不能直接使用类名非访问静态方法或属性
}

元数据

dart
// 元数据以@开头可以给代码标记一些额外的信息,仅作为一个标注和提示,对代码运行无影响
// @override(重写) 某方法添加该注解后表示重写了父类中同名方法

// @required(必填) 可以通过它来注解 Dart 中的命名参数,用来指示它是必填参数

// @deprecated(弃用) 若某类或方法加上此注解后,表示此方法或类不再建议使用
class Phone {
  // 这表示 activate 即将被弃用
  @deprecated
  activate(){
    turnOn();
  }
  turnOn(){
    print('开机');
  }
}

void main() {
  Phone p = Phone();
  p.activate();
}

继承

dart
void main() {
  zi z = zi();
  print(z.name);
}

class fu {
  String name = '大黄';
  void jiao() {
    print('jiao');
  }
}

class zi extends fu {}

继承的特点

dart
// dart 的继承是单继承,一个子类只能有一个父类

// 子类只会继承父类中可见的属性和方法,不会继承私有方法和属性

// 子类只会继承父类默认的构造函数,不会继承其他构造函数,这时子类需要定义自己的构造函数
void main() {
  zi z = zi('小花');
  print(z.name);
}

class fu {
  String name = '大黄';
  // 如果父类有自定义类名构造函数,那么子类必须创建构造函数
  fu(this.name);
  void jiao() {
    print('jiao');
  }
}

class zi extends fu {
  // 可以通过 super 调用父类的构造函数
  zi(String name) : super(name);
}

// 子类可以重写父类的方法,也可以使用super调用父类方法
void main() {
  zi z = zi('小花');
  print(z.name);
  z.jiao();
}

class fu {
  String name = '大黄';
  fu(this.name);
  void jiao() {
    print('jiao');
  }
}

class zi extends fu {
  zi(String name) : super(name);
  // 重写父类方法
  @override
  void jiao() {
    print('重写父类方法');
    // 如果需要父类方法的逻辑可以通过 super 调用父类方法
    super.jiao();
  }
  // 如果子类只想实现一个新的父类方法,可以这样写,到时候 z.jiao() 执行的是这个函数
  void jiao() {
    print('jiao2');
  }
}

抽象类

dart
// 抽象类不能被实例化
// 通过 abstract 声明抽象类用来做类的模板
abstract class Phone {
  // 抽象类中可以没有抽象方法也可以有
  void processor(); // 声明抽象方法
  void camera(); // 声明抽象方法
  void info() {
    print('抽象类中可以有普通方法');
  }
}

class Xiaomi extends Phone {
  // 普通类中不能有抽象方法
  // 普通类继承抽象类必须实现抽象类中所有的抽象方法
  // 使用元数据标记这是一个重写的方法
  @override
  void processor() {
    print('骁龙888');
  }

  @override
  void camera() {
    print('三星');
  }
}

void main() {
  Xiaomi p = Xiaomi();
  p.processor();
}

接口

dart
// 接口就是一个类,接口可以是任意类,但一般使用抽象类做接口
// 一个类可以实现(implements)多个接口
// 普通类实现接口后必须重写接口所有的属性和方法
// 使用抽象类来当做接口
abstract class Processor {
  late String cores;
  arch(String name);
}

abstract class Camera {
  late String resolution;
  brand(String name);
}

// 通过普通类来实现接口
class Phone implements Processor, Camera {
  // 实现属性
  String cores;
  String resolution;
  // 实现方法
  @override
  arch(String name) {
    print('实现接口');
  }

  @override
  brand(String name) {
    print('实现接口');
  }

  Phone(this.cores, this.resolution);
}

void main() {
  Phone p = Phone('2', '3');
  p.brand('3');
  p.arch('3');
}

mixin

dart
// 可以为类扩展功能,而不需要使用继承,类似于 vue2 中的混入
// 可以扩展属性和方法
// 不能被实例化,不能被继承
// 使用多个混入时后引入的混入会覆盖之前混入中重复的内容
dart
void main() {
  zi z = zi();
  s s1 = s();
  fu f = fu();
  z.walk();
  s1.walk();
  f.walk();
  print(f.sex);
}

// 定义 mixin
mixin WalkMixin {
  void walk() {
    print('walk');
  }
}
// 定义 mixin
mixin sexMixin {
  String sex = '男';
}

// 可以使用多个 mixin
class fu with WalkMixin, sexMixin {
  String name = '大黄';
  void jiao() {
    print('jiao');
  }
}

class s with WalkMixin {}

class zi extends fu with WalkMixin {
  void jiao() {
    print('jiao2');
  }
}

////////////////////////////////////////////////////////////////////////
// 通过类的方式声明混入,这种方式 MixinA 不能继承除 Object 之外的类,也不能有构造函数
class MixinA {
  String name = 'MixinA';
  printA() {
    print(name);
  }
}

// 通过 mixin 关键字声明混入
mixin MixinB {
  String name = 'MixinB';
  printB() {
    print(name);
  }
}

class Myclass with MixinB, MixinA {}

void main() {
  Myclass p = Myclass();
  // 使用多个混入时后引入的混入会覆盖之前混入中重复的内容
  print(p.name); // MixinA
  p.printA(); // MixinA
  p.printB(); // MixinA
}

异步编程

dart
import 'dart:io';

void main() {
  print('开始执行');
  // Future 可以用来解决异步编程问题,写在这里的耗时任务不会立即执行
  Future(() {
    // 耗时任务执行的地方
    sleep(Duration(seconds: 5)); // 表示程序在这里会延时 5 秒,本身 sleep 是同步代码
    // dynamic s = 'hehe';这里是故意写错的程序
    // s.haha();这里是故意写错的程序
    return '这是异步任务执行的结果';
  })
      .then((value) => {
            // 这里表示异步任务执行完成就会执行这里,value 可以接收到异步任务返回的数据
            print(value)
          })
      .catchError((error) {
    // 这里可以捕获异步任务的错误
    print(error);
  });
  print('假装这是不能被阻塞的代码');
}

链式调用

dart
import 'dart:io';

void main() {
  // 必须先登录才能保存用户信息
  Future login(String name, String password) {
    return Future(() {
      sleep(Duration(seconds: 2));
      print('登陆操作');
      return 'userinfo';
    });
  }

  Future saveinfo(String info) {
    return Future(() {
      sleep(Duration(seconds: 2));
      print('保存用户信息');
      return 'ok';
    });
  }

  login('zhang', '123').then((value) => {
    saveinfo(value)
  });
}

async 简化

dart
import 'dart:io';

void main() {
  // 必须先登录才能保存用户信息
  Future login(String name, String password) {
    return Future(() {
      sleep(Duration(seconds: 2));
      print('登陆操作');
      return 'userinfo';
    });
  }

  Future saveinfo(String info) {
    return Future(() {
      sleep(Duration(seconds: 2));
      print('保存用户信息');
      return 'ok';
    });
  }

  // login('zhang', '123').then((value) => {
    // saveinfo(value)
  // });

  // 使用 async await 简写上面的写法
  getinfo() async {
    String info = await login('zhang', '123');
    await saveinfo(info);
  }
}

泛型

使用泛型指定类型

dart
void main() {
  // List arr = ['s',1,true]; 不指定泛型时 List 是可以存储任意类型的元素的
  List<String> arr = ['s', '2']; // 通过泛型指定 List 中保存指定类型
  // 不指定泛型时 Map 中 key 可以是任意类型
  // Map obj = {'id': 1, 'name': "居家", 1: 2, true: 1};
  // 使用泛型指定 Map 键和值的类型
  Map<String, String> obj = {'id': '1', 'name': "居家", '1': '2', 'true': '1'};
  // 还可以这样写
  List a = <int>[2,3];
  Map m = <String,String>{
    '2':''
  };
}

使用泛型简化代码

dart
void main() {
  String s(String str) {
    return str;
  }

  int a(int str) {
    return str;
  }

  // 上面的两个函数可以利用泛型写成一个
  T d<T>(T info) {
    return info;
  }
}

// 泛型类
class P<T> {
  getinfro(T s) {
    print(s);
  }
}

void main() {
  P p = P<String>();
  p.getinfro('2');
}

泛型类型限制

dart
class Somether {}

class Anoth {}

// 限制参数类型必须继承 Somether 或 Somether 子类
class Foo<T extends Somether> {
  getinfo() {
    print(T);
  }
}

void main() {
  Foo f = new Foo<Somether>();
  f.getinfo();
}

异常

dart
void main() {
  try {
    dynamic a = 'ss';
    a.haha();
  } catch (error) {
    print('出错');
  } finally {
    // 无论是否出现异常都会执行这里的代码
  }
  String s = 'zxc';
  if (s == 'zxc1') {
    print('ok');
  } else {
    // 手动抛出异常
    throw '字符串不相等';
  }
}

dart 库与生态

dart
// https://pub.flutter-io.cn/ 对标js中的 npm

自定义库

dart
// 每个 Dart 文件默认都是一个库,只是没有使用 library 来显示声明
// Dart 使用 _(下划线)开头的标识符,表示库内访问可见(私有)
// library 关键字声明的库名称建议使用: 小写字母 + 下划线

index.dart

dart
import './test.dart';

void main() {
  Dog m = new Dog();
  print(m.name);
}

test.dart

dart
// library 关键字声明的库名称建议使用: 小写字母 + 下划线
library my_dog;

class Dog {
  String name = '小名';
  void info() {
    print('自定义库');
  }
}

系统库

dart
// import 'dart:系统库名称';
import 'dart:math';
// import 'dart:core'; // core 库即使不手动引入也会默认引入
void main() {
  print(pi); // 3.141592653589793   获取圆周率
  print(min(3, 6)); // 3
  print(max(3, 6)); // 6
}

按需引入

dart
// show 表示只引入后续的内容(除了后续指定的内容,其他的都不引入)
import './test.dart' show f1, f3;
// hide 表示隐藏后面的内容(除了后续指定的内容,其他的都引入)
import './test.dart' hide f1, f3;

void main() {
  f2();
}

引入冲突

dart
import './test.dart';
// 当多个包里的名称重名时使用 as 添加前缀解决
import './test2.dart' as test2;

void main() {
  f2();
  test2.f2();
}

test.dart

dart
f2() {
  print('f2');
}

test2.dart

dart
f2() {
  print('f2');
}

异步引入(懒加载)

dart
// 异步加载此时只是和该库建立联系并未真正引入
import './test.dart' deferred as func;

void main() {
  greet();
}

Future greet() async {
  // loadLibrary 函数返回一个 Future 表示等待库引入,这时可以使用 async 或者 then 来指定引入完成后要干的事
  await func.loadLibrary();
  func.f1();
}

主库和分库

分库使用 part of 和主库建立联系,主库使用 part 和分库建立联系,最终组成一个完整的库