Appearance
简介
官方文档 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 和分库建立联系,最终组成一个完整的库