基础语法
Hello world!
Dart
void main(List<String> args) {
print("hello world");
}
注意:{}后不用加分号
变量与常量的声明
var (当存储数据发生变化,需要用变量var来声明)语法:var 变量名=值/表达式
Dart
void main(List<String> args) {
var age = 20;//第一次赋值以后,类型被确定,后面不允许更改为其他类型
print(age);
age = 2;
print(age);
var age1 = 20 + 21;
print(age1);
}
//依次输出20 2 41
const (一开始就是被确定的,且不允许更改,表达式不允许存在变量值) 语法:const=值/表达式
final (场景:当我们需要当前时间作为唯一的操作时间,时间一旦确定就不可以被修改)
语法:final=值/表达式
Dart
void main(List<String> args) {
final time = DateTime.now();//运行时不可被修改,const编译确定,不可修改
time = DateTime.now();
print(time);
}
//这么写就会报错
总结const和final:
- final 是运行时常量(可以在运行时获取值),值在第一次使用时确定。const 是编译时常量(必须在编译时就能推算出结果),值在代码编译时就已经完全确定。
- 当需要存储一个不变的数据,且编译时就确定,用const(如字符串、数字、固定的配置列表、不变的 UI 组件),但是在运行时才确定,用final(如当前时间、网络请求结果、用户输入、依赖其他变量计算的结果)
常用数据类型
- 字符串-String
String 属性名='文本内容'; 引号支持单引号或者双引号,支持拼接及模板字符串
Dart
void main(List<String> args) {
String text = "今天是个好日子"; //是个变量 var
print(text);
text = "明天也是个好日子";
print(text);
}
//会打印两行
模板字符串 语法:String 属性名='文本内容变量名'; 或String 变量名 ='文本内容{变量名}';
模板内容是表达式更推荐${}
Dart
void main(List<String> args) {
//我要在当前的时间吃饭
String content = '我要在${DateTime.now()}吃饭';
print(content);
}
如果是单独变量,可以直接$变量名
Dart
String a="张三";
String content="我和$a是好朋友";
- 数字-int/double/num
int 整数
int 整数 num 可小数可整数 double 小数
Dart
void main(List<String> args) {
int friendcount = 3;
print("我有$friendcount个朋友");
double apple = 1.5;
num rest = 1.3;
//double 和 int 不能直接赋值 eg:friendcount=apple 是不允许的
//friendcount = apple.toInt();//但可以转换形式后在赋值,反之也行
//num也不可直接给double赋值
//double可直接赋值给num
rest = apple;//无报错
}
- Bool类型
列表(List)
场景:当一个变量需要存储多个值的时候,可以用列表类型List
语法:List 属性名='stu1','stu2';
常用操作方法或属性:
- 在尾部添加-add(内容)
- 在尾部添加一个列表-addAll(列表)
- 删除满足内容的第一个-remove(内容)
- 删除最后一个-removeLast()
- 删除索引范围内数据 -removeRange(start,end),结束索引不包含在索引范围内,如要删除,再往后推一位。
- 循环-forEach((item) {});
- 是否都满足条件-every((item) {return 布尔值}
- 筛选满足条件的数据-where((item) {return 布尔值})
- 列表的长度-length
- 最后一个元素(属性)-last
- 第一个元素(属性)-first
- 是否为空(属性)-isEmpty
where 是用来「筛选」的,它会把符合条件的元素挑出来,返回一个新集合。
every 是用来「判断」的,它会检查是否所有元素都符合条件,返回一个 true 或 false。
在使用 every 时,只要遇到第一个不满足条件的元素,它就会立刻返回 false,不会再去检查后面的元素。这在处理大型列表时能节省性能。
Dart
//输出hello world
void main(List<String> args) {
List student = ['张三', '李四', '赵五'];
student.add('新同学');
List stu2 = ['A', 'B', 'C'];
student.addAll(stu2);
student.forEach((item) {
print(item); //循环打印
});
//是否所有的同学都已新开头
print(
student.every((item) {
return item.toString().startsWith('新');
}),
);
//筛选出以新开头的同学,并转换为一个列表
student.where((item) {
return item.toString().startsWith('新');
}).toList();
}
Map
场景:当存储的英文需要找到对应的中文描述,需要使用键值对类型Map
语法1:Map 属性名 ={key :value};
语法2:字典key可以取值和赋值
Dart
void main(List<String> args) {
Map transMap = {"lunch": '午饭', "moring": '早上', "hello": '你好'};
//通过英文找到对应的中文描述
print(transMap["lunch"]);
transMap["hello"] = "你非常好";
print(transMap["hello"]);
}
Map的常用操作方法
- 循环-forEach
- 再添加一个字典-addAll
- 是否包含某一个key-containsKey
- 删除某个key-remove
- 清空-clear
Dart
void main(List<String> args) {
Map transMap = {"lunch": '午饭', "moring": '早上', "hello": '你好'};
//通过英文找到对应的中文描述
print(transMap["lunch"]);
transMap["hello"] = "你非常好";
print(transMap["hello"]);
//字典有很多对应对应关系,
transMap.forEach((key, value) {
print("$key $value");
});
//addAll 给当前字典添加一个字典
transMap.addAll({"fine": '非常好'});
print(transMap);
//containKey判断字典中是否包含某个key
print(transMap.containsKey("fine"));
transMap.remove("fine");
print(transMap);
//清空字典
transMap.clear();
print(transMap);
}
动态类型-dynamic
特点:运行变量运行时自由改变类型,同时绕过编译时的的静态检查。
语法1:dynamic 属性名 =值;
与var 的区别:dynamic运行时可随意改变类型,无编译检查,方法和属性直接调用,var根据初始值进行推断类型,确定类型后类型确定,有编译检查,仅限推断的方法和属性。
空安全机制
定义:通过编译静态检查将运行时的空指针提前暴露
特点:将空指针异常从运行时提前至编译前,减少线上崩溃

Dart
void main(List<String> args) {
String? username = null; //? 表示变量可空
username?.startsWith("a"); //前面变量有可能为空时,代码不会读后面的属性和方法
//客观判断
//sername = "张三";
//主观判断,开发者一定认为username不为null
username!.startsWith("a");
//要保证别人一定显示用户名
String displayName = username ?? "老高";//如果username有值,显示username,反之显示老高
}
算术运算符
与c语言相同,注意使用整除(~/)时,属性命名不要用double,整除得到的是int类型。
赋值运算符
与c相同
比较运算符
特点:比较运算符得到的结果都是bool类型。其余与c相同。
逻辑运算符
定义:对bool类型进行逻辑运算
&& 逻辑与
|| 逻辑或
! 逻辑非(取反)
流程控制
If分支语句
Dart
void main(List<String> args) {
int source = 61;
if (source > 60) {
print("恭喜及格");
} else if (source > 80) {
print("恭喜优秀");
} else {
print("不及格");
}
}
三元运算符 语法:表达式(bool值)?结果1:结果2;
switch/case
Dart
void main(List<String> args) {
int state = 1; // 1 待付款 2 待发货 3 待收货
switch (state) {
case 1:
print("待付款");
break;
case 2:
print("待发货");
break;
case 3:
print("待收货");
break;
default:
print("未知");
}
}
while循环
break跳出整个while循环,continue是跳出当前迭代,进入下一次迭代。
Dart
void main(List<String> args) {
List foods = ["第一个包子", "第二个包子", "第三个包子", "第四个包子", "第五个包子"];
int index = 0;
while (index < foods.length) {
if (index == 2) {
break;
}
print(foods[index]);
index += 1;
}
}
for循环
Dart
void main(List<String> args) {
List foods = ["第一个包子", "第二个包子", "第三个包子", "第四个包子", "第五个包子"];
for (var i = 0; i < foods.length; i++) {
if (i == 2) {
continue;
}
print(foods[i]);
}
}
函数
Dart
//返回类型 函数名称 参数 函数体
int add(int a, int b) {
return a + b;
}
分类:
有返回值:具体类型 函数名称(){}
无返回值:void 函数名称 (){}
返回类型可省略,Dart会自动推断类型为dynamic(动态类型,可以为任何类型,不好推断返回值类型)
参数
分为必传参数,可选位置参数,可选命令参数。
特点:
- 必传参数不为空
- 可选位置参数必须位于必传参数后面,采用中括号包裹
Dart
//合并字符串
String combiong(String a, [String? b, String? c]) {
return a + (b ?? "默认值b") + (c ?? "默认值c");
}
- 可选命名参数必须位于必传参数后面,采用大括号包裹
Dart
void showPerson(String username, {int? age, String? sex}) {
print("姓名:$username,年龄:$age,性别:$sex");
}
与可选位置参数可设置默认值
匿名函数
特点:可以生成一个没有名称的函数赋值给变量,进行调用
语法:Function 变量名=(){};
注意:函数类型用Function来声明
Dart
void main(List<String> args) {
oneTest(test);
}
//声明一个匿名函数赋值test变量
Function test = () {
print("测试数据");
};
//还可以当作参数传递,执行,调用
void oneTest(Function callback) {
callback();
}
箭头函数
特点:函数体只有一行代码
语法:函数名()=>代码逻辑
注意:可省略return关键字
Dart
int add(int a, int b) => a + b;
类(class)
定义:包含属性和方法来定义对象的行为和状态
定义类方法:class Person {属性 方法}
实例化对象:Person 变量=Person();
属性和方法:变量.属性/方法()
Dart
class Person {
String name = "";
int age = 0;
String sex = "男";
void study() {
print("$name在学习");
}
}
构造函数
定义:实例化对象的时候,使用构造函数直接给对象中的属性赋值
常见分类:默认构造函数,命名构造函数,构造函数的语法糖
默认构造函数
Dart
void main(List<String> args) {
Person p = Person(name: '老高', age: 12, 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在学习");
}
}
给类赋值时只需写一行,参数一一对应,提升代码可读性。
命名构造函数
定义:构造函数可以采用命名的方式,返回一个实例化对象
语法:
class 类名{
类名.构造函数名(可选命名参数){}
}
实例化语法:Person p=Person.构造函数名(属性:值)
Dart
Person.createPerson({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}
构造函数的语法糖
定义:同名构造函数和命名构造函数都支持简写写法
语法:
class 类名{
类名({this.属性1,this.属性2});
或
类名.命名函数({this.属性1,this.属性2});
}
Dart
Person({this.name, this.age, this.sex});
公有属性和私有属性
共有属性:提供自身或其他外部文件和类使用的属性和方法
私有属性:仅供自身使用的属性和方法,其他外部文件和类无法访问
语法:私有属性以下滑线开头,如_name,其余均为公有属性
继承
定义:拥有父类的属性和方法
特点:dart属于单继承,一个类只能拥有一个直接父类,子类拥有父类所有的属性和方法
语法:class 类名 extends 父类
重写:子类可以通过@override注解重写父类方法,扩展其行为
注意:子类不会继承父类的构造函数,子类必须通过super关键字调用父类构造函数确保父类正确初始化
super语法:子类构造函数(可选命名参数):super({参数})
Dart
void main(List<String> args) {
Child c = Child(name: 'a', age: 1);
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() {
//super.study();
print('子类$name在学习');
}
}
多态
定义:Dart中的类的是指同一操作作用于不同对象,可以产生不同的执行效果
场景:微信和支付宝都遵循同样的支付接口,但实现逻辑不同。
实现方法:
1.继承和方法重写
Dart
void main(List<String> args) {
PayBase wx = WxPay();
wx.pay();
}
//父类
class PayBase {
void pay() {
print("基础支付");
}
}
//子类
class WxPay extends PayBase {
@override
void pay() {
print("微信支付");
}
}
class AliPay extends PayBase {
@override
void pay() {
print("支付宝支付");
}
}
2.抽象类和接口
方法:使用abstract关键字声明一个抽象类(没有实现体)
使用implements关键字继承并实现抽象类
Dart
void main(List<String> args) {
Paybase wx = WxPay();
Paybase Ali = AliPay();
wx.pay();
Ali.pay();
}
abstract class Paybase {
void pay(); //抽象类是不写具体实现的
}
//wx支付
class WxPay implements Paybase {
@override
void pay() {
print("微信支付");
}
}
//支付宝支付
class AliPay implements Paybase {
@override
void pay() {
print("支付宝支付");
}
}
混入
定义:Dart允许在不使用穿透继承的情况下,向类中添加新的功能
方法:使用mixin关键字定义一个对象
方法:使用with关键字将定义的对象混入到当前的对象
特点:一个类支持with多个mixin,调用优先级遵循"后来居上"原则,即后混入的会覆盖先混入的同名方法
需求(eg):让一个学生类和老师类都拥有唱歌的方法
Dart
import 'dart:collection';
void main(List<String> args) {
Student s = Student(name:"AA");
s.song(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});
}
泛型
定义:Dart允许使用类型参数,限定类型的同时又让类型更加灵活。
场景(eg):List类型中只想存储String类型怎么办?函数返回值希望和参数一个类型怎么办?
常见分类:泛型集合,泛型方法,泛型类
Dart
import 'dart:collection';
void main(List<String> args) {
//列表泛型 或者Map
List<String> list = [];
Map<String, int> map = {};
}
//函数中的方法
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是单线程语言,即同时只能做一件事,遇到耗时任务会导致程序阻塞,因此需要异步编程
定义:单线程+事件循环
事件循环:
执行同步代码------>执行微任务队列------>执行实践队列------>结束
微任务队列:Future.microtask()
事件队列:Future,Future.delayed(),I/O操作(文件,网络)等
Future
介绍:代表一个异步操作的最终结果
状态:Uncompleted(等待),Conpleted 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((onError) {
print("出现错误");
});
}
Future链式调用
介绍:Future可以通过链式的方法连续得到异步的结果
语法:通过Future().then()拿到执行成功的结果
语法:通过Future().catchError()拿到执行失败的结果
注意:在上一个then返回对象会在下一个then中接受
需求:执行三个异步任务,按照顺序排列,最后一次抛出异常
Dart
import 'dart:io';
void main(List<String> args) {
//链式调用
Future f = Future(() {
return "Hello Flutter";
});
//then接受成功状态
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(error);
});
}
async/await
介绍:除了then和catchError的方式,还有async和await来实现异步编程
特点:await总是等后面的Future执行成功,才执行下方逻辑,async必须配套await出现
语法:
函数名()async{
try{
await Future();
//Future执行成功才执行的逻辑
}
catch(error){
//执行失败的逻辑
}
}
Dart
void main(List<String> args) {
test();
}
void test() async {
try {
String result = await Future(() {
return "测试";
});
print(result);
} catch (e) {
print("异步请求出现异常");
}
}