Appearance
Dart 语言基础
变量和常量
变量声明(var)
场景:当一个人的年龄从20岁变成21岁,存储数据发生变化,需要用变量来进行声明
关键字:var
语法:
dart
var 变量名 = 值/表达式;注意:使用var声明的变量,其类型在第一次赋值之后确定,不能再赋值其他类型的值
dart
void main(List<String> args) {
var age = 20; //第一次赋值之后,类型被确定,后边不能再赋值其他类型
print(age); // 20
age = 21;
print(age); // 21
var age1 = 20 + 21; //还可以为表达式
print(age1); // 41
}常量声明(const)
场景:当做圆形计算的时候,π的值一开始就是被确定的,且不允许更改,使用const进行声明
关键字:const
语法:const 属性名 = 值/表达式;
特点:const是代码编译前被确定,不允许表达式中有变量存在,必须为常量或者固定值
dart
void main(List<String> args) {
const num = 3.1415926;
// num = 3.14; //不允许修改常量的值
const length = 2 * num * 10; //计算圆的周长
// const 表达式里面的值不允许有变量
// const width = length / 2; //错误写法
}运行时常量(final)
场景:当我们需要当前时间作为当前唯一的操作时间,时间一旦被确定就不可以被修改。
关键字:final
语法:final 属性名 = 值/表达式;
特点:final变量在运行时被初始化,其值设置后不可更改
dart
void main(List<String> args) {
final time = DateTime.now(); //运行时不可以被修改 const在编译时就确定,不可以被修改
// time = DateTime.now(); // 会报错,因为 final 变量不能被重新赋值
print('Current time: $time');
// Current time: 2025-10-22 02:47:55.388169
}总结
变量:当需要存储一个变化的数据需要使用var来声明变量
编译时常量:当需要存储一个不变的数据,且在编译时就确定,需要使用const声明常量
运行时常量:当需要存储一个不变的数据,但是在运行时才确定,需要使用final声明常量
常用数据类型
字符串类型(String)
场景:当我们需要用一个变量来描述一段文本,就可以使用String来声明。
关键字:String
语法:String 属性名 = ‘文本内容’;
特点:引号支持双引号或者单引号,支持拼接及模板字符串
dart
void main(List<String> args) {
String text = '今天是个好日子'; //是个变量 var
print(text); //'今天是个好日子'
text = '明天也是个好日子'; //变量可以修改
print(text); //'明天也是个好日子'
}模板字符串
场景:当String类型的变量当前时间来显示,可以使用模板字符串或者拼接实现。
需求:打印出我要在(具体时间)的时候吃早饭
语法:String 属性名 = ‘文本内容$变量名’; 或 String 变量名 = ‘文本内容${变量名}’;
注意:当存在模板中的内容是一个表达式的时候需要使用${}, 更推荐使用${}
dart
void main(List<String> args) {
String text = "今天是个好日子"; // 是个变量 var
print(text);
text = "明天同样是个好日子";
print(text);
// 我要在当前的时间吃饭
String content = '我要在${DateTime.now()}吃饭';
print(content);
String flag = "张三";
String content1 = '我和$flag是好朋友';
print(content1);
}数字类型(int/num/double)
场景:当我们需要描述一个数字类型的时候,需要使用int/num/double
区别:int-整型数字,num-可整型可小数,double-小数
语法:int/num/double 属性名 = 数值;
数字类型赋值关系
注意:数字之间的赋值关系
double和int不能直接赋值
num不能直接给double赋值
double可直接给num赋值
dart
void main(List<String> args) {
// int
// num
// double
int friendCount = 3;
print('我有$friendCount个朋友');
num rest = 1.5;
print('我有$rest月的假期');
double appleCount = 1.5;
print('我买了$appleCount斤苹果');
//friendCount = appleCount; // 不允许直接赋值
//friendCount = appleCount.toInt();
appleCount = friendCount.toDouble();
appleCount = rest.toDouble(); // num可以转化成double给double赋值
rest = appleCount; // double可以直接给num赋值
}布尔类型(bool)
场景:当我们需要一个属性来表示当前为真(true)或假(false)的时候,需要使用bool关键字声明
需求:声明当前自己是否已经完成作业
语法:bool 属性名 = true/false;
dart
void main(List<String> args) {
// 定义一个布尔类型的变量,表示同学的作业状态
bool isFinishWork = false;
print("同学当前的作业状态是$isFinishWork");
// 修改变量的值,表示同学已经完成作业
isFinishWork = true;
print("同学当前的作业状态是$isFinishWork");
}列表类型(List)
场景:当一个变量需要存储多个值的时候,可以使用列表类型List
需求:一个班级的学生用List存储,支持对学生的查找、新增、删除、循环
语法:List 属性名 = [‘学生1’, ‘学生2’];
列表常用操作
在尾部添加-add(内容)
在尾部添加一个列表-addAll(列表)
删除满足内容的第一个-remove(内容)
删除最后一个-removeLast()
删除索引范围内数据-removeRange(start,end)
注意:end不包含在删除范围内
循环-forEach((item) {});
是否都满足条件-every((item) { return 布尔值 });
筛选出满足条件的数据-where((item) { return 布尔值 });
列表的长度(属性)-length
最后一个元素(属性)-last
第一个元素(属性)-first
是否为空(属性)-isEmpty
dart
void main(List<String> args) {
List students = ["张三", "李四", "王五"];
print(students);
students.add("新同学"); // 在尾部进行添加
students.add("新同学"); // 在尾部进行添加
print(students);
students.addAll(["新来的同学1", "新来的同学2"]); // 在尾部添加一个列表
print(students);
students.remove("新同学"); // 删除满足内容的第一个
print(students);
// 删除最后一个同学
students.removeLast(); // 删除最后一个
print(students);
// 删除前两个同学
// start开始的索引 end结束的索引-不包含在删除范围内
students.removeRange(0, 2);
print(students);
// forEach针对每个列表每个数据进行操作
students.forEach((item) {
// 书写逻辑
print(item);
});
// 是不是所有的同学都以新为开头
print(
students.every((item) {
return item.toString().startsWith("新"); // 返回一个条件
}),
);
// 筛选出所有的以新开头的同学呢
print(
students.where((item) {
return item.toString().startsWith("新");
}).toList(),
);
// List常用的一些属性 方法() .属性
print(students.length);
print(students.last); // 列表的最后一个
print(students.first); // 列表的第一个
print(students.isEmpty); // 列表是否是空的
}字典类型(Map)
场景:当存储的英文需要找到对应的中文描述,需要使用键值对类型Map
需求:需要定义一个英文对应中文的描述,并可以通过英文找到对应的中文
语法1:Map 属性名 = { key: value };
语法2: 字典[key] 可以取值和赋值
字典常用操作
循环-forEach
在添加一个字典-addAll
是否包含某个key-containsKey
删除某个key-remove
清空-clear
dart
void main(List<String> args) {
Map transMap = {"lunch": '午饭', "morning": "早上", "hello": '你好'};
print(transMap);
// 通过英文找到对应中文的描述
print(transMap["morning"]);
transMap["hello"] = "你非常好";
print(transMap["hello"]);
// 字典里面有很多对应关系
transMap.forEach((key, value) {
print("$key,$value");
});
// addAll 给当前字典添加一个字典
transMap.addAll({"fine": "非常好"});
print(transMap);
// containesKey判断字典中是否包含某个key
print(transMap.containsKey("fine"));
transMap.remove("fine");
print(transMap);
// 清空字典
transMap.clear();
print(transMap);
}动态类型(dynamic)
定义:Dart语言中,dynamic用来声明动态类型
特点:允许变量运行时自由改变类型, 同时绕过编译时的静态检查
语法1:dynamic 属性名 = 值;
dart
void main(List<String> args) {
// 自由设置类型
dynamic free = 1;
free = "";
free = false;
free = [];
free = {};
}动态类型与var的区别
dynamic: 运行时可自由改变类型,无编译检查,方法和属性直接调用
var: 根据初始值进行推断类型,确定类型后类型确定,有编译检查,仅限推断的属性和方法
dart
void main(List<String> args) {
// 自由设置类型
var text = 1;
text.toDouble(); // 1.0
// 虽然运行报错,但是绕过编译,不会提示
dynamic text1 = 1;
text1.startsWith("");
//Unhandled exception:NoSuchMethodError: Class 'int' has no instance method 'startsWith'.
}空安全机制
定义:在Dart语言中,通过编译静态检查将运行时空指针提前暴露
特点:将空指针异常从运行时提前至编译时,减少线上崩溃
常用空安全操作符
| 操作符 | 符号 | 作用 | 示例 |
|---|---|---|---|
| 可空类型 | ? | 声明可空变量 | String?→ 允许 String或 null |
| 安全访问 | ?. | 对象为 null时跳过操作,返回 null | user?.name→ 若 user为 null则返回 null |
| 非空断言 | !. | 开发者保证变量非空(否则运行时崩溃) | name!.length→ 断言 name非空 |
| 空合并 | ?? | 左侧为 null时返回右侧默认值 | name ?? "Guest"→ name为 null时返回 |
dart
void main(List<String> args) {
String? username = null; // 可空类型
username?.length; // 安全访问
username!.length; // 非空断言
username ?? "老高"; // 空合并
}运算符
算术运算符
定义:在Dart语言中,对数字进行加减乘除运算采用算术运算符
| 运算符 | 作用 |
|---|---|
| + | 加 |
| - | 减 |
| * | 乘 |
| / | 除 |
| ~/ | 整除 |
| % | 取余数 |
dart
void main(List<String> args) {
//乘
double item = 10.99;
double allPrice = item * 4;
print(allPrice);
//减
double money = 100;
double lastMoney = money - allPrice;
print(lastMoney);
//除
// double everyMoney = lastMoney / 4;
//整除
int everyMoney = lastMoney ~/ 4;
print(everyMoney);
//取余数
print(10 % 4);
}赋值运算符
定义:在Dart语言中,对数据进行赋值运算采用赋值运算符
| 运算符 | 作用 |
|---|---|
| = | 赋值操作 |
| += | 加等,a += b 相等于 a = a + b |
| -= | 减等, a -= b 相等于 a = a - b |
| *= | 乘等, a *= b 相等于 a = a * b |
| /= | 除等, a /= b 相等于 a = a / b |
dart
void main(List<String> args) {
double a = 1; // 赋值运算符
a += 2; // a = a + 2
print(a);
a -= 1; // a = a - 1
print(a);
a *= 2; // a = a * 2
print(a);
a /= 2; // a = a / 2;
print(a);
}比较运算符
| 运算符 | 作用 |
|---|---|
| == | 判断两个值是否相等 |
| != | 判断两个值是否不等 |
| > | 判断左侧值是否大于右侧值 |
| >= | 判断左侧值是否大于等于右侧值 |
| < | 判断左侧值是否小于右侧值 |
| <= | 判断左侧值是否小于等于右侧值 |
dart
void main(List<String> args) {
int a = 1;
int b = 2;
print(a == b);
print(a != b);
print(a > b);
print(a >= b);
print(a < b);
print(a <= b);
}比较运算符
定义:在Dart语言中,需要对于bool类型的值进行逻辑运算,需要使用逻辑运算符
| 运算符 | 作用 |
|---|---|
| && | 逻辑与,a && b, a和b同时true,得true |
| || | 逻辑或,a || b,a和b有一个true,得true |
| ! | 逻辑非,!a,对a变量进行取反 |
注意: 使用逻辑运算符必须保证参与的变量为布尔类型
dart
void main(List<String> args) {
// 逻辑运算符
bool isOpenDoor = false; // 是否开门
bool isOpenLight = true; // 是否开灯
// 门和灯同时打开
print(isOpenDoor && isOpenLight);
print(isOpenDoor || isOpenLight); // 门和灯至少打开一个
print(!isOpenDoor);
print(!isOpenLight);
}流程控制
if分支语句
定义:在Dart语言中,if分支语句可以进行不同逻辑的判断和处理
| if分支 | 作用 |
|---|---|
| 单分支 | 单个条件判断 |
| 双分支 | 两个条件判断 |
| 多分支 | 多个条件判断 |
dart
void main(List<String> args) {
int score = 81;
// 单条件情况
if (score > 60) {
print("恭喜你及格");
}
// 双分支
bool isMarry = false;
if (isMarry) {
print("恭喜你成家");
} else {
print("还没结婚哦");
}
// 多分支
if (score > 80) {
print("优秀");
} else if (score >= 60) {
print("及格");
} else {
print("不及格");
}
}三元运算符
定义:在Dart语言中,三元运算符是一种简化版本的双分支语句
语法:
dart
表达式(布尔值) ?结果1 :结果2;dart
void main(List<String> args) {
// 三元运算符中不能再写if else
print(59 >= 60 ? "及格" : '不及格');
}switch-case语句
定义:在Dart语言中,如果分支条件很多,且条件是判断相等,可以使用switch case语句
语法:
dart
switch(变量) {
case 值1:
逻辑1;
break;
case 值2:
逻辑2;
break;
default:
默认逻辑;dart
void main(List<String> args) {
int state = 100; // 1 代付款 2 待发货 3 待收货 4 待评价 5 未知状态
switch (state) {
case 1:
print("待付款");
break;
case 2:
print("待发货");
break;
case 3:
print("待收货");
break;
case 4:
print("待评价");
break;
default:
print("未知状态");
}
}循环语句
while循环
定义:在Dart语言中,循环主要使用while循环和for循环
dart
while(条件) {
逻辑;
}特点:只有条件满足,括号中逻辑一直执行,想要跳出执行使用break或者continue
注意: break是跳出整个while循环,continue是跳出当前迭代,进入下一次迭代
dart
void main(List<String> args) {
List foods = [
"第一个包子",
"第二个包子",
"第三个包子",
"第四个包子",
"第五个包子", // 4
];
int index = 0;
while (index < foods.length) {
if (index == 2) {
// break; // break跳出整个循环
index += 1;
continue; // 跳出当前迭代
}
print(foods[index]);
index += 1;
}
// 第一种场景 吃到第二个的时候 就已经吃饱了 跳出整个循环使用break;
// 第二种场景 要开始吃第三个包子的时候 包子里有个虫子 跳过第三个 要接着吃第四五个
}变体
dart
do{
循环体
}while(条件);dart
void main(List<String> args) {
int x = 1;
int total = 0;
// while 循环
// while(x<=100){
// total += x;
// x++;
// }
// do while 循环
do {
total += x;
x++;
} while (x <= 100);
print(total);
}for循环
定义:在Dart语言中,for循环可以对列表类型进行遍历
for循环语法:
dart
for(变量初始化; 判定条件; 完成循环体后得操作) {
逻辑;
}特点:只有小括号逻辑满足,大括号逻辑一直执行,想要跳出执行使用break或者continue
注意: break是跳出整个while循环,continue是跳出当前迭代,进入下一次迭代
dart
void main(List<String> args) {
List foods = [
"第一个包子",
"第二个包子",
"第三个包子",
"第四个包子",
"第五个包子", // 4
];
for (var i = 0; i < foods.length; i++) {
// 吃两个吃饱了
if (i == 2) {
// break; 跳出整个循环
continue; // 跳出当前迭代
}
print(foods[i]);
}
}集合类型对象得遍历——for in
结构:
dart
for(变量 in 集合){
循环体
}dart
void main(List<String> args) {
List col = [1, 2, 3, 4, 5];
for (var item in col) {
print(item);
}
//1 2 3 4 5
}函数
函数定义
定义:在Dart语言中,函数是代码组合和复用的核心单元
场景:应用程序中很多地方需要做两数之和的运算,可以定义函数来组织代码
函数返回值
分类:函数返回值分为有返回值和无返回值
有返回值: 具体类型 函数名称() {}
无返回值: void 函数名称() {}
注意: 返回值类型可省略,Dart会自动推断类型为dynamic
推荐: 虽然返回值可省略,明确返回值类型是更推荐的编程习惯
dart
void main(List<String> args) {
print(add(1, 2, 3));
test();
}
// 返回类型 函数名称 参数 函数体
// int 表示返回值是整数类型
int add(int a, int b, int c) {
return a + b + c;
}
// 无返回值类型 使用void表示
void test() {
print("测试无返回值数据");
}
// 返回值类型可以省略,Dart会自动推断类型为动态类型dynamic
getValue() {
return 1 + 2;
}函数参数
必传参数
分类:函数的参数分为必传参数,可选位置参数,可选命名参数
特点:必传参数不能为空
dart
void main(List<String> args) {
add(1, 2);
}
int add(int a, int b) {
return a + b;
}可选位置参数
特点:可选位置参数必须位于必传参数后面, 采用中括号包裹
语法:函数名(String a, [ String? b, ... ]),传递时按照顺序传递
适用场景:参数少且顺序固定时
默认值:可选参数可以设置默认值
dart
void main(List<String> args) {
print(combine("1"));
}
// 合并字符串
String combine(String a, [String? b = "b", String? c = "c"]) {
return a + (b ?? "") + (c ?? "");
}可选命名参数
特点:可选命名参数必须位于必传参数后面, 采用大括号包裹
语法:函数名(String a, { String? b, ...}),传递时按照 参数名:值的方式进行传递,无需关注顺序
适用场景:参数多且需明确含义时
默认值:可选参数可以设置默认值
dart
void main(List<String> args) {
showPerson("老高", sex: "男");
}
void showPerson(String username, {int? age = 18, String? sex = "男"}) {
print('姓名:$username, 年龄: $age,性别: $sex');
}匿名函数
特点:可以声明一个没有名称的函数赋值给变量,进行调用
语法: Function 变量名 = () { };
注意:函数的类型使用Function来声明
dart
void main(List<String> args) {
// test();
onTest(test);
}
// 声明了一个匿名函数赋值test变量
Function test = () {
print("测试数据");
};
void onTest(Function callback) {
callback();
}箭头函数
特点:当函数体只有一行代码时,可以使用箭头函数编写
语法:函数名 () => 代码逻辑
注意:使用箭头函数可以省略return关键字
dart
int add(int a, int b) => a + b;类
类的定义
定义:Dart语言中,类(class)是面向对象编程的核心,类包含属性和方法来定义对象的行为和状态
需求: 定义一个Person类,属性包括姓名、年龄、性别,包括学习的方法
定义类语法:
dart
class Person { 属性 方法 }实例化对象:
dart
Person 变量 = Person();属性和方法: 变量.属性/方法()
dart
void main(List<String> args) {
Person p = Person();
p.name = "老高";
p.study();
}
class Person {
String name = ""; // 姓名
int age = 0; // 年龄
String sex = "男";
void study() {
print("$name在学习");
}
// void study() => print("$name在学习"); // 箭头函数简写
}类的构造函数
默认构造函数
定义:实例化对象的时候,使用构造函数直接给对象中的属性赋值
常见分类: 默认构造函数、命名构造函数、构造函数的语法糖
定义语法:
dart
class 类名 {
类名(可选命名参数) {
}
}实例化语法:
Person p = new Person(属性: 值)
dart
void main(List<String> args) {
Person p = Person(name: '老高', age: 20, sex: '男');
p.study();
Person pp = Person(name: '小张', age: 20, sex: '男');
pp.study();
}
class Person {
String? name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男";
//默认构造函数
Person({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}
void study() {
print("$name在学习");
}
}命名构造函数
定义:构造函数可以采用命名的方式,返回一个实例化对象
定义语法:
dart
class 类名 {
类名.构造函数名(可选命名参数) {
}
}实例化语法:
Person p = Person.构造函数名(属性: 值)
dart
void main(List<String> args) {
Person ppp = Person.createPerson(name: '新同学', age: 30);
ppp.study();
}
class Person {
String? name = ""; // 姓名(可空类型,默认空字符串)
int? age = 0; // 年龄(可空类型,默认0)
String? sex = "男"; // 性别(可空类型,默认"男")
// 构造函数(使用命名参数)
Person({String? name, int? age, String? sex}) {
this.name = name; // 将参数赋值给成员变量
this.age = age;
this.sex = sex;
}
// 学习方法
void study() {
print("$name在学习"); // 打印"姓名在学习"
}
}注意:默认构造函数和命名构造函数可同时存在
dart
void main(List<String> args) {
Person p = Person(name: '老高', age: 20, sex: '男');
// p.name = "老高";
p.study();
Person pp = Person(name: '小张', age: 20, sex: '男');
pp.study();
Person ppp = Person.createPerson(name: '新同学', age: 30);
ppp.study();
}
class Person {
String? name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男";
//默认构造函数
Person({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 命名构造函数
Person.createPerson({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}
void study() {
print("$name在学习");
}
}语法糖
定义:同名构造函数和命名构造函数都支持简写写法
语法:
dart
class 类名 {
类名({ this.属性1,this.属性2 });
或
类名.命名函数({ this.属性1,this.属性2 });
}dart
void main(List<String> args) {
Person p = Person(name: '老高', age: 20, sex: '男');
// p.name = "老高";
p.study();
Person pp = Person(name: '小张', age: 20, sex: '男');
pp.study();
Person ppp = Person.createPerson(name: '新同学', age: 30);
ppp.study();
}
class Person {
String? name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男";
//默认构造函数
// Person({String? name, int? age, String? sex}) {
// this.name = name;
// this.age = age;
// this.sex = sex;
// }
Person({this.age, this.name, this.sex}); // 语法糖写法
// 命名构造函数
Person.createPerson({this.age, this.name, this.sex});
// Person.createPerson({String? name, int? age, String? sex}) {
// this.name = name;
// this.age = age;
// this.sex = sex;
// }
void study() {
print("$name在学习");
}
}类的公有和私有属性
公有属性,提供自身或者其他外部文件和类使用的属性和方法
私有属性,仅供自身使用的属性和方法,其他外部文件和类无法访问
语法:私有属性以下划线开头, 如_name,其余均为公有属性
dart
import './类的私有属性.dart';
void main(List<String> args) {
Person p = Person.createPerson(name: '老高');
// p.study();
// p._study();
// p._name = "";
}dart
//类的私有属性.dart
class Person {
String? _name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男";
//默认构造函数
// 命名构造函数
Person.createPerson({String? name, int? age, String? sex}) {
this._name = name;
this.age = age;
this.sex = sex;
}
void _study() {
print("$_name在学习");
}
}类的继承
定义:继承是拥有父类的属性和方法
特点:dart属于单继承,一个类只能拥有一个直接父类, 子类拥有父类所有的属性和方法
语法:class 类名 extends 父类
重写:子类可通过@override注解重写父类方法,扩展其行为
注意:子类不会继承父类构造函数,子类必须通过super关键字调用父类构造函数确保父类正确初始化
super语法: 子类构造函数(可选命名参数) : super({ 参数 })
dart
void main(List<String> args) {
Child c = Child(name: '老高', age: 20);
c.study();
}
// 父类
class Parent {
String? name;
int? age;
Parent({this.name, this.age});
void study() {
print('父类-$name在学习');
}
}
// 子类继承父类
class Child extends Parent {
Child({String? name, int? age}) : super(name: name, age: age);
@override
void study() {
// TODO: implement study
// super.study(); // 先调用了父类的方法
print("子类-$name在学习");
}
}类的多态
继承和方法重写
定义:Dart中的类的是指同一操作作用于不同的对象,可以产生不同的执行效果
场景:微信和支付宝都遵循同样支付接口,但实现逻辑不同,即同一个支付操作拥有不同的支付效果
实现方式:1.继承和方法重写 、2. 抽象类和接口
需求:定义一个父类,分别实现微信和支付宝支付类,重写得到不同的支付逻辑
dart
void main(List<String> args) {
Child c = Child(name: '老高', age: 20);
c.study();
}
// 父类
class Parent {
String? name;
int? age;
Parent({this.name, this.age});
void study() {
print('父类-$name在学习');
}
}
// 子类继承父类
class Child extends Parent {
Child({String? name, int? age}) : super(name: name, age: age);
@override
void study() {
// TODO: implement study
// super.study(); // 先调用了父类的方法
print("子类-$name在学习");
}
}抽象类和接口
方式:使用abstract关键字声明一个抽象类(没有实现体)
方式:使用implements关键字继承并实现抽象类
dart
void main(List<String> args) {
PayBase wx = WxPay();
PayBase ali = AliPay();
wx.pay();
ali.pay();
}
abstract class PayBase {
void pay(); // 抽象类是不写具体实现的
}
// 微信支付
class WxPay implements PayBase {
@override
void pay() {
// TODO: implement pay
print("微信支付");
}
}
// 支付宝支付
class AliPay implements PayBase {
@override
void pay() {
// TODO: implement pay
print("支付宝支付");
}
}类的混入
定义:Dart允许在不使用传统继承的情况下,向类中添加新的功能
方式:使用mixin关键字定义一个对象
方式:使用with关键字将定义的对象混入到当前对象
特点:一个类支持with多个mixin,调用优先级遵循“后来居上”原则,即后混入的会覆盖先混入的同名方法
需求:让一个学生类和一个老师类都拥有唱歌的方法
dart
void main(List<String> args) {
PayBase wx = WxPay();
wx.pay();
PayBase ali = AliPay();
ali.pay();
}
// 基础支付类
class PayBase {
void pay() {
print("基础支付");
}
}
// 微信支付类
class WxPay extends PayBase {
@override
void pay() {
// TODO: implement pay
// super.pay();
print("微信支付");
}
}
// 支付宝支付类
class AliPay extends PayBase {
@override
void pay() {
// TODO: implement pay
// super.pay();
print("支付宝支付");
}
}泛型
定义:Dart允许使用类型参数,限定类型的同时又让类型更加灵活,让代码更加健壮和维护性更强
场景:List类型中只想存储String类型怎么办?函数中返回值希望和参数一个类型怎么办?
常见分类: 泛型集合、泛型方法、泛型类
dart
void main(List<String> args) {
// 列表泛型 或者Map
List<String> list = [];
list.add("");
// list.add(1);
// list.add(false);
// list.add([]);
Map<String, int> map = {};
map["a"] = 1;
getValue<String>("1");
printList<String>(["1", "2", "3"]);
Student<int> s = Student();
s.name = 1;
}
// 函数中的方法
T getValue<T>(T value) {
return value;
}
void printList<T>(List<T> list) {
for (var i = 0; i < list.length; i++) {
print(list[i]);
}
}
class Student<T> {
T? name;
}异步编程
事件循环
介绍:Dart是单线程语言,即同时只能做一件事,遇到耗时任务就会造成程序阻塞,此时需要异步编程
定义:Dart采用单线程 + 事件循环的机制完成耗时任务的处理
事件循环:
微任务队列:Future.microtask()
事件队列:Future、Future.delayed()、I/O 操作(文件、网络) 等
微任务队列 + 事件队列都属于异步任务
Future
介绍:Future代表一个异步操作的最终结果.
状态:Uncompleted(等待)、Completed with a value (成功)、Completed with a error(失败)
创建: Future(() {})
执行成功:不抛出异常-成功状态-then(() {})
执行失败: throw Exception()-失败状态-catchError(() {})
dart
void main(List<String> args) {
Future f = Future(() {
// return "Hello Flutter";
// 没有抛出异常 那就是成功状态
throw Exception();
});
// then中接收成功状态
f.then((value) {
print(value);
});
f.catchError((error) {
print("出现错误了");
});
}Future链式调用
介绍:Future可以通过链式的方式连续得到异步的结果
语法:通过Future().then() 拿到执行成功的结果
语法:通过Future().catchError() 拿到执行失败的结果
注意:在上一个then返回对象会在下一个then中接收
需求:执行三个异步任务,按照顺序排列,最后一次任务抛出异常
dart
void main(List<String> args) {
// 三个异步任务 采用链式调用的方式来实现
Future f = Future(() {
return "Hello World";
});
f.then((value) {
// 第一个任务
return Future(() => "task1");
})
.then((value) {
// 第二个任务
return Future(() => "$value-task2");
})
.then((value) {
// 第三个任务
return Future(() => "$value-task3");
})
.then((value) {
print(value);
throw Exception("异常");
})
.catchError((error) {
print("出现错误");
});
}Future-async/await
介绍:除了通过then/catchError的方式,还可以通过async/await来实现异步编程
特点: await 总是等到后面的Future执行成功,才执行下方逻辑,async必须配套await出现
语法:
dart
函数名 () async {
try {
await Future();
// Future执行成功才执行的逻辑
}
catch(error) {
// 执行失败的逻辑
}
}dart
void main(List<String> args) {
test(); // 调用函数
}
void test() async {
try {
String result = await Future(() {
return "测试";
// throw Exception();
});
// await Future.delayed(Duration(seconds: 3));
// await下方的逻辑 永远是Future执行成功之后执行的
print(result);
} catch (e) {
print("异步请求出现异常");
}
}