Dart 语言注意事项
- 文件后缀 .dart
- 入口方法为 main 方法
- dart 文件中绝大部分语句都需要分号,像 '{}' 后通常不需要
声明类型
1. 变量声明:var
- 使用 var 声明的变量,其类型在第一次赋值之后确定,不能再赋其他类型的值
2. 常量声明:
- const:编译时确定
- final:运行时确定
- 表达式里不允许有变量值;一旦确定,不可修改
3. 字符串型:String
4. 数字类型:
- int:整形
- num:可整型可小数
- double:小数
5. 布尔类型:bool
6. 列表类型:List
-
与数组用法一样,但注意名称
-
常用方法1:
- add(内容) 尾部添加
- addAll(列表) 尾部添加一个列表
- remove(内容) 删除满足内容的第一个
- removeLast()删除最后一个
- removeRange(start, end) 删除索引范围内的数据-左闭右开
-
常用方法2:
- 循环 foeEach((item){})
- 是否都满足条件 every,有返回值(布尔值)
- 筛选出满足条件的数据 where,有返回值(布尔值),最终会得到一个类似列表的数据,用toList()方法转换
- 列表的长度 length
- 最后一个元素 last
- 第一个元素 first
- 是否为空 isEmpty
7. 字典类型:Map
-
场景:存储的英文需要找到对应的中文描述
-
常用方法:
- 循环 forEach((key, value){})
- 尾添一个字典 addAll
- 是否包含某个key containsKey
- 删除某个key remove
- 清空 clear
8. 动态类型:dynamic
-
允许变量运行时自由改变类型,同时绕过编译时的静态检查
-
模版字符串:变量名、{变量名或表达式} 在单引号内即可
-
获取当前时间:DateTime.now()
空安全机制
- 定义:在Dart语言中,通过编译静态检查将运行时空指针提前暴露
| 操作符 | 符号 | 作用 | 示例 |
|---|---|---|---|
| 可空类型 | ? |
声明可空变量 | String?(允许 String 或 null) |
| 安全访问 | ?. |
对象为 null 时跳过操作,返回 null | user?.name(若 user 为 null 则返回 null) |
| 非空断言 | !. |
开发者保证变量非空(否则运行时崩溃) | name!.length(断言 name 非空) |
| 空合并 | ?? |
左侧为 null 时返回右侧默认值 | name??"Guest(name 为 null 时返回 "Guest") |
//shuchuhello
void main(List<String> args) {
String? username = null;
// 计算机帮我们判断是否为空
username?.startsWith('前');
// 开发者主观判断一定不为空(这段代码中运行时是会正常报错的,运行前没报错而已)
username!.startsWith('前');
// 因为前面已经主观判定username不为空,所以name一定不是"前天"
String name = username ?? '前天';
print(name);
}
函数
1. 函数参数
- 可选参数:位于必传参数后面,用中括号包裹
- 语法:函数名(String a, [String?b, ...]),传递时按顺序传递
- 适用于参数少且顺序固定
javascript
String combine(String a, [String? b, String? c]){
return a + (b ?? "一") + (c ?? "天");
}
- 可选命名参数:位于必传参数后面,用大括号包裹
- 语法:函数名(String a, {String?b, ...}),传递时按 参数名:值 的方式传递,顺序不重要
- 适用于参数多且需明确含义
javascript
void main(List<String> args) {
person("老王", sex: "男", age: 20);
}
// 若不传age、性别,会为null,设置默认值好点
void person(String username, {int? age = 18, String? sex = "男"}) {
print('姓名:${username},年龄:${age},性别:${sex}');
}
2. 匿名函数
- 可以声明一个没有名称的函数赋值给变量,进行调用
- 语法:Function 变量名 = (){}
javascript
void main(List<String> args) {
Function add = () {
print('这是匿名函数');
};
add();
}
3. 箭头函数
- 语法:函数名()=>代码逻辑
scss
void main(List<String> args) {
print(test('这是箭头函数'));
print1();
}
String test(String a) => a;
void print1() => print('Hello');
类-class
- 定义类语法:class 类名 { 属性 方法 }
- 实例化对象:类名 变量名 = 类名();
- 属性和方法:变量.属性/方法();
ini
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在学习');
}
}
类-构造函数
实例化对象的时候,使用构造函数直接给对象中的属性赋值
1. 默认构造函数:
- 定义语法:
arduino
class 类名 {
类名(可选命名参数){
}
}
- 实例化语法:Person p = new Person(属性: 值)
ini
void main(List<String> args) {
Person p = Person(name: "老王", age: 20, sex: "男");
p.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在学习');
}
}
2. 命名构造函数
- 定义语法:
arduino
class 类名 {
类名.构造函数名(可选命名参数){
}
}
- 实例化语法:Person p = new Person.构造函数名(属性: 值)
ini
void main(List<String> args) {
Person p = Person.createPerson(name: "老王", age: 20, sex: "男");
p.study();
}
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在学习');
}
}
3. 构造函数语法糖
- 简写语法:
kotlin
class 类名 {
类名({this.属性1, this.属性2});
类名.构造函数名({this.属性1, this.属性2});
}
类-公有属性和私有属性
以下划线开头为私有属性,如_name,其余均为公有属性
类-继承
继承是拥有父类的属性和方法,dart属于单继承,一个类只能拥有一个直接父类,子类拥有父类所有的属性和方法
- 语法:class 类名 extends 父类
- 重写:子类可通过@override注解重写父类方法,扩展其行为
- 注意:子类不会继承父类构造函数,子类必须通过super关键字调用父类构造函数确保父类正确初始化
- super语法:子类构造函数(可选命名参数): super({参数})
dart
void main(List<String> args) {
Child p = Child(name: "老王", age: 20);
p.study();
}
class Person {
String? name = "";
int? age = 0;
// 命名构造函数
Person({this.name, this.age});
void study() {
print('$name在学习');
}
}
class Child extends Person {
Child({String? name, int? age}) : super(name: name, age: age);
@override
void study() {
// TODO: implement ==
// super.study();调用父类方法
print('子类-$name在学习');
}
}
类的多态
- 继承和方法重写
- 抽象类和接口
- 使用abstract关键字声明一个抽象类(没有实现体),使用implements关键字继承并实现抽象类
typescript
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() {
print("微信支付");
}
}
class AliPay implements PayBase {
@override
void pay() {
print("支付宝支付");
}
}
类的混入
Dart允许在不使用传统继承的情况下,向类中添加新的功能
- 方法:使用mixin关键字定义一个对象,使用with关键字将定义的对象混入到当前对象
scala
void main(List<String> args) {
Student s = Student(name: '小华');
s.song(s.name!); // 设置s.name不可能为空
}
// 定义一个混入对象
mixin Base {
void song(String name) {
print('$name在唱歌');
}
}
class Student with Base {
String? name;
int? age;
Student({this.name, this.age});
}
class Teacher with Base {
String? name;
int? age;
Teacher({this.name, this.age});
}
- 注意:一个类支持with多个mixin,调用优先级遵循"后来居上"原则
泛型
- 定义:Dart允许使用类型参数,限定类型的同时又让类型更加灵活,让代码更加健壮和维护性更强
- 列表泛型:List<类型> 变量名 = []
- 字典泛型:Map<String, int> map = {}; 里面分别是键、值类型
- 函数泛型
csharp
void main(List<String> args) {
print(getValue<String>("1"));
print(getList<String>(["1", '2']));
}
T getValue<T>(T value) {
return value;
}
T getList<T>(List<T> value) {
return value[0];
}
- 类里的泛型
ini
void main(List<String> args) {
Student<int> s = Student();
s.name = 1;
}
class Student<T> {
T? name;
}
Dart中的异步编程
Dart是单线程语言,同时只能做一件事,遇到耗时任务就会造成程序阻塞,此时需要异步编程
- 微任务队列:Future.microtask()
- 事件队列:Future、Future.delayed()、I/O操作等
1. Future
- Future代表一个异步操作的最终结果
- 状态:Uncompleted等待、Completed with a value成功、Completed with a error失败
- 创建语法:Future((){})
- 执行成功:不抛出异常-成功状态、catchError((){})
- 执行失败:throw Exception()-失败状态-catchError((){})
javascript
void main(List<String> args) {
// 定义一个Future对象
Future f = Future(() {
return "hello";
// 没有抛出错误 就是成功状态
// throw Exception();
});
f.then((value) {
print(value);
});
// f.catchError((err) {
// print("出错了");
// });
}
- 链式调用
javascript
void main(List<String> args) {
Future(
() => "hello",
)
.then((value) => throw Exception())
.catchError((err) => print("出错wu了"));
}
2. async/await
- await总是等到后面的Future执行成功,才执行下方逻辑,async必须配套await出现
- 语法:
scss
函数名()async{
try{
await Future();
// Future执行成功才执行的逻辑
}
catch(error){
// 执行失败的逻辑
}
}
- 补充:
Future.delayed(Duration(seconds:3))delayed延时函数,Duration时间对象,所以这里是延时3秒