Dart语言
1.环境搭建
下载Dart SDK:gekorm.com/dart-window…
按软件包的方式来安装,最新的Dart会自动配置环境变量,
2.基础知识
2.1.变量和常量的声明
- 变量
void main(List<String> args) {
var age = 20; // 值
print(age);
age = 21;
var age1 = 20 + 21; // 表达式
print(age1);
}
注意:
- 变量使用
var声明 - 变量第一次赋值之后,其类型不能改变,即第一次赋值为字符串类型的话,其只能后面给字符串类型的值
- 常量
void main(List<String> args) {
const num = 3.1415926;
const length = 2 * num * 10;
print(length);
}
void main(List<String> args) {
final time = DateTime.now();
print(time);
}
注意:
- 常量的值如果是表达式,则表达式中不能有变量
- 常量不能由变量赋值
- const 赋值要求是编译时就确定的值
- final 是运行时被初始化,其值设置后不可更改
2.2.Dart类型
- 字符串类型
void main(List<String> args) {
// 基本使用
String text = '今天是个好日子';
print(text);
text = '明天同样是一个好日子';
print(text);
// 模板字符串
String content = '我要在${DateTime.now()}吃饭';
print(content);
String flag = '张三';
content = '我和$flag是好朋友';
print(content);
}
- 数值类型
int:整数
num:可以是整数,也可以是小数
double:小数
void main(List<String> args) {
int friendCount = 3;
print('我有$friendCount个朋友');
num rest = 1.5;
print('我有$rest个假期');
double appleCount = 1.5;
print('我要买$appleCount斤的苹果');
friendCount = appleCount.toInt(); // int 和 double 之间不允许进行相互的赋值
appleCount = friendCount.toDouble();
rest = appleCount; // double可以直接赋值给num
appleCount = rest.toDouble(); // num给double赋值要进行转换
}
注意:
- double 、int 类型之间不能直接赋值,需要通过
toInt()、toDoublue()来进行转换【Dart不能隐式转换】 - num不能直接给double赋值,而double可以直接赋值给num
- bool 类型
void main(List<String> args) {
bool isFinishWork = false;
print('结束任务的状态$isFinishWork');
}
- List列表类型
void main(List<String> args) {
List students = ['张三', '李四', '王五'];
print(students);
// 在尾部添加内容
students.add('小美');
print(students);
// 在尾部添加列表
students.addAll(['赵六', '小豪']);
print(students);
// 删除满足内容的第一个
students.remove('小豪');
print(students);
// 删除最后一个
students.removeLast();
print(students);
// 删除索引范围的数据【不删除结束索引位置的元素】
students.removeRange(0, 2);
print(students);
}
void main(List<String> args) {
List students = ['张三', '*李四', '*王五'];
print(students);
// 遍历列表
students.forEach((item) {
print(item);
});
// 是否都满足条件
var isReal = students.every((item) {
return item.toString().startsWith('*');
});
print(isReal);
// 筛选出满足条件的数据【这里返回的是一个类似于列表类型的数据,所以要转换为列表】
var isStars = students.where((item) {
return item.toString().startsWith('*');
}).toList();
print(isStars);
// list的常用属性
print(students.length); // 长度
print(students.first); // 获取第一个元素
print(students.last); // 获取最后一个元素
print(students.isEmpty); // 判断列表是否为空
}
- Map 字典类型
void main(List<String> args) {
Map transMap = {'lunch': '午饭', 'breakfast': '早餐', 'hello': '你好'};
print(transMap);
// 通过key获取值
print(transMap['lunch']);
// 修改值
transMap['hello'] = '你非常好';
print(transMap);
// 循环字典
transMap.forEach((key, val) {
print('$key:$val');
});
// 再添加一个字典
transMap.addAll({'fine': '很好'});
print(transMap);
// 判断字典中是否包含某个key
print(transMap.containsKey('fine'));
// 删除某个key
print(transMap.remove('fine'));
// 清空
transMap.clear();
print(transMap);
}
- dynamic动态类型
特点:允许变量再运行时自由的改变类型,同时绕过编译时的静态检查
void main(List<String> args) {
dynamic free = '字符串';
free = 123;
free = {};
free = [];
free = true;
print(free);
}
- dynamic可以自由的改变类型,无编译检查,方法和属性直接调用
2.3.Dart的空安全机制
Dart通过编译静态检查将运行时的空指针提前暴露
常用的空安全的操作符:
void main(List<String> args) {
// 表示变量可空
String? username = null;
// 表示前面的变量为null的时候,跳过操作
username?.startsWith('新');
// 表示开发者保证前面的变量不为空
username!.startsWith('牢');
// 左侧为null时返回右侧默认值
String displayName = username ?? '老高';
print(displayName);
}
2.4.运算符
2.5.流程控制
- 分支语句 和 三元运算符
void main(List<String> args) {
// 表示变量可空
int score = 61;
if (score >= 60) {
print('及格');
} else if (score > 70) {
print('良好');
} else if (score < 60) {
print('不及格');
}
print(59 >= 60 ? '及格' : '不及格');
}
void main(List<String> args) {
// 表示变量可空
int state = 1;
switch (state) {
case 1:
print('情况1');
break;
case 2:
print('情况2');
break;
case 3:
print('情况3');
break;
default:
print('你好');
}
}
- 循环控制
while(条件) {
循环体
}
continue // 跳出当前循环
break // 跳出整个循环
for(int i = 0; i < 10;i++) {
循环体
}
3.Dart的函数
返回类型 函数名称(参数列表) {
函数体
}
void main(List<String> args) {
var number = add(1, 2, 3);
print(number);
}
int add(int a, int b, int c) {
return a + b + c;
}
3.1.函数的参数
- 可选位置参数
void main(List<String> args) {
print(combine('1', '2'));
}
// 可选位置参数
// 可以给对应可选参数设置默认值
String combine(String a, [String? b, String? c = 'c']) {
return a + (b ?? "") + (c ?? "");
}
- 可选命名参数
void main(List<String> args) {
print(combine('1', '2'));
showPerson("老高", sex: '男');
}
// 可选位置参数
// 可以给对应可选参数设置默认值
String combine(String a, [String? b, String? c = 'c']) {
return a + (b ?? "") + (c ?? "");
}
// 可选命名参数
void showPerson(String username, {int? age, String? sex}) {
print('姓名:$username,性别:$sex,年龄:$age');
}
注意:可选命名参数无需关注参数的位置,它是按照参数的名称来传递对应的参数值
3.2.匿名函数
Function 变量名 = () {}
void main(List<String> args) {
test();
// 传入函数类型的参数
onTest(test);
}
Function test = () {
print('测试数据');
};
void onTest(Function callback) {
callback();
}
3.3.箭头函数
当函数体只有一行代码逻辑的时候,可以使用箭头函数编写,箭头函数可以省略return关键字
函数名 => 代码逻辑
void main(List<String> args) {
test();
// 传入函数类型的参数
onTest(test);
add(1, 2);
}
Function test = () {
print('测试数据');
};
void onTest(Function callback) {
callback();
}
// 箭头函数
int add(int a, int b) => a + b;
4.类
void main(List<String> args) {
Person p = new Person();
p.name = '小天';
p.study();
}
class Person {
String name = '';
int age = 0;
String sex = '男';
void study() {
print('$name在学习');
}
}
4.1.类的构造函数
- 默认构造函数
void main(List<String> args) {
Person p = new Person(name: '小天', age: 15, sex: '男');
p.study();
Person pp = new Person(name: '老天', age: 15, 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在学习');
}
}
- 命名构造函数
void main(List<String> args) {
Person p = new Person(name: '小天', age: 15, sex: '男');
p.study();
Person pp = new Person(name: '老天', age: 15, sex: '男');
pp.study();
Person ppp = new Person.createPerson(name: '小白', age: 15, sex: '男');
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在学习');
}
}
- 构造函数的语法糖(其不要求参数的顺序)
void main(List<String> args) {
Person p = new Person(name: '小天', age: 15, sex: '男');
p.study();
Person pp = new Person(name: '老天', age: 15, sex: '男');
pp.study();
Person ppp = new Person.createPerson(name: '小白', age: 15, sex: '男');
ppp.study();
}
class Person {
String? name = '';
int? age = 0;
String? sex = '男';
// 语法糖
Person({this.name, this.age, this.sex});
Person.createPerson({this.name, this.age, this.sex});
void study() {
print('$name在学习');
}
}
4.2.面向对象的三种性质
1.封装
公有属性和私有属性
私有属性:属性名以下划线开头的属性都是私有属性,包括私有方法,方法名称只要以下划线开头即可
私有属性和私有方法只能在类的内部访问,外部引入不能使用
2.继承
Dart属于单继承
注意:子类不会继承父类的构造函数,子类必须通过super关键字调用父类的构造函数来确保父类正确初始化
void main(List<String> args) {
Child c = Child(name:'小天',age:15);
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() {
// 调用父类的study()
super.study();
print('子类的$name在学习');
}
}
多态
- 继承和重写方法
void main(List<String> args) {
PayBase p = WxPay();
p.pay();
PayBase pp = AliPay();
pp.pay();
}
class PayBase {
void pay() {
print('基础支付');
}
}
class WxPay extends PayBase {
@override
void pay() {
print('wx支付');
}
}
class AliPay extends PayBase {
@override
void pay() {
print('zfb支付');
}
}
- 抽象类和接口实现
void main(List<String> args) {
PayBase p = WxPay();
PayBase pp = AliPay();
p.pay();
pp.pay();
}
abstract class PayBase {
void pay(); // 抽象类不屑具体实现
}
class WxPay implements PayBase {
@override
void pay() {
print('wx支付');
}
}
class AliPay implements PayBase {
@override
void pay() {
print('zfb支付');
}
}
4.3.类的混入
Dart允许在不使用传统的继承的方式下,向类中添加新的功能
方式:
- 使用mixin关键字定义一个对象
- 使用with关键字将定义的对象混入到当前的对象
特点:一个类支持with多个mixin,调用优先级遵循后来者居上,即后混入的会覆盖先混入的同名方法
void main(List<String> args) {
Student s = Student(name: '小天');
s.song(s.name!);
Teacher t = Teacher(name: '小百');
t.song(t.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});
}
5.泛型
void main(List<String> args) {
// 列表泛型
List<String> list = [];
list.add('苹果');
list.add('香蕉');
// 字典泛型
Map<String, int> map = {};
map['a'] = 10;
print(getValue<String>('1'));
}
// 函数中的泛型
T getValue<T>(T val) {
return val;
}
// 类使用泛型
class Student<T> {
T? name;
}
6.异步编程
Dart 是单线程语言,即同时只能做一件事情,遇到耗时任务就会造成程序堵塞,此时需要异步编程
定义:Dart采用单线程+事件循环的机制来完成耗时任务的处理
事件循环:
Dart会先去执行同步代码,然后去执行微任务队列中的任务,然后再去执行事件队列中的事件最后才会执行结束
- 微任务队列:Future.microtask()
- 事件队列:Future、Future.delayed()、I/O操作(文件、网络)等
6.1.Future
Future代表一个异步操作的最终结果
状态:Uncompleted(等待)、Completed with a value(成功)、Completed with a error(失败)
void main(List<String> args) {
Future f = Future(() {
throw Exception();
// return 'Hello Future';
// 没有抛出异常,则表示是成功状态
});
// value是Future你返回的值
// then接收成功状态
f.then((value) {
print(value);
});
// catchError接收失败状态
f.catchError((err) {
print('出现错误了');
print(err);
});
}
- 链式调用
void main(List<String> args) {
// 三个异步任务使用链式调用
Future f =
Future(() {
return 'Hello world';
})
.then((value) {
return Future(() => 'task1');
})
.then((val) {
return Future(() => '$val task2');
})
.then((val) {
return Future(() => '$val task3');
})
.then((val) {
print(val);
throw Exception();
})
// 只要一个有异常就会直接跳到异常这里的处理
.catchError((err) {
print('出现错误');
});
}
- async/await
注意:async 和 await必须配套出现
await总是要等到后面的Future执行成功才继续执行下方逻辑
void main(List<String> args) {
test();
}
void test() async {
try {
await Future(() {
throw Exception();
});
} catch (err) {
print('异步请求出现异常');
}
}
void main(List<String> args) {
test();
}
void test() async {
try {
String res = await Future(() {
return 'test';
});
print(res);
} catch (err) {
print('异步请求出现异常');
}
}