Skip to content

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时跳过操作,返回 nulluser?.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("异步请求出现异常");
  }
}