Dart是强类型语言支持指定类型(内置类型和自定义类型),也支持动态类型推导。
Dart中所有变量都是对象类型(所有类型都是Object的子类,包括Function和Null),Dart初始值为null。
Dart定义变量和数据类型(泛型):
支持指定类型(内置类型和自定义类型),变量初始化为一种数据类型,不能将其他数据类型赋值给该变量(dynamic除外),支持类型推导。
类型推导变量
var
关键字声明变量,编译时确定类型(初始化类型后不能更改,不推荐使用)。
var a = 1;
(指定内置类型变量)
dynamic
关键字声明变量并指定运行时类型(赋值后可以更改类型)。
dynamic a1 = 1;
a1 = true;
a1 = '123';
String
关键字声明变量并指定编译时类型(字符串类型)
String a2 = '1';
num
关键字声明变量并指定编译时类型(数字类型,不推荐 )
num a3 = 1;
int
关键字声明变量并指定编译时类型(整数类型)
int a4 = 1;
double
关键字声明变量并指定编译时类型(浮点数类型)
double a5 = 1.0;
bool
关键字声明变量并指定编译时类型(布尔类型)
bool a6 = true;
List
关键字声明变量并指定编译时类型(列表类型)
List a7 = [1, '2', true]; // 列表(数组)
List a8 = <String>['1', '2']; // 泛型列表(数组)
List a9 = List.filled(2, ''); // 固定长度列表(数组)
List a10 = List<int>.filled(2, 1); // 泛型固定长度列表(数组)
Map
关键字声明变量并指定编译时类型(映射类型)
Map a11 = {'name': '张三', 'age': 20}; // Maps映射
Set
关键字声明变量并指定编译时类型(集合类型)
Set a12 = {}; // Set集合
Function
关键字声明变量并指定编译时类型(函数类型)
Function a13 = ((){
return(){};
})();
自定义关键字声明变量并指定编译时类型一般在类中运用较多(自定义类型)。
Dart定义常量:类型推导常量和指定类型常量
final 声明常量,运行时确定常量(只初始化类型一次)。
const 声明常量,编译时确定常量。
final b1 = DateTime.now();
const 声明常量,编译时确定常量。
/* 常量构造函数 */
class Fish {
/* 成员变量都是final修饰 */
final int a;
void b() {}
/* 构造函数用const修饰 */
const Fish(this.a);
const Fish.play(this.a);
Fish b6 = const Fish(1); // 实例化常量构造函数
const b7 = Fish(1);// 和上面一样,另一种写法
}
const b2 = 1;
Set b3 = const {}; // 声明常量集合
Map b4 = const {}; // 声明常量映射
List b5 = const [1, 2, 3]; // 声明常量列表
final 类型关键字 声明常量并指定运行时常量类型。
final DateTime b7 = DateTime.now();
String b8 = 'aaa';
final int b9 = b3.length;
const 类型关键字 声明常量并指定编译时常量类型。
const int b10 = 1;
操作符
String? c; // 可为空操作符
print(c?.length); // 可选操作符
print(c!.length); // 类型断言操作符
List c1 = [1, 2, 3];
dynamic c2;
List c3 = [...c1, 4, 5, 6]; // [1, 2, 3, 4, 5, 6] 扩展运算符
List c4 = [1, 2, 3, ...?c2]; // [1, 2, 3] 空感知运算符
class C {
String name = '小红';
int age = 18;
String sex = '女';
}
C c5 = C();
c5..name = '张三'..age = 20..sex = '男'; // 级联操作符
dynamic c6;
c6 ??= 12; // b6没有被赋值,则b6被赋值12,b6有值,不做操作。
int c7 = c6 ?? 10; // b6没有值,则10赋值给b7,b6有值,则b6赋值给b7。
Dart类型转换:
toString() 其他类型(一般是Number类型)转String类型
parse() 其他类型(一般是String类型)转Number类型
toList() 其他类型转List类型
join(‘’) 数组转字符串(返回值String类型)
split(‘’) 字符串转数组(返回值List类型)
as 类型转换(类型推导错误,手动指定类型)
int d1 = 1;
String d2 = '1';
List d3 = [1, 2, 3];
print(d1.toString() == '1'); // true
print(int.parse(d2) == 1); // true
print(d3.reversed); // (3, 2, 1)
print(d3.reversed.toList()); // [3, 2, 1]
print(d3.join('-')); // 1-2-3
print(d2.split('')); // [1]
Dart类型判断:
isEmpty 判断是否为空
isNotEmpty 判断是否不为空
isNaN 判断是不是NaN
isOdd 判断是不是奇数
isEven 判断是不是偶数
is 关键词判断类型
if判断
switch case判断
List e1 = [];
int e2 = 12;
print(e2.isNaN); // false
print(e2.isEven); // true
print(e2.isOdd); // false
print(e1.isEmpty); // true
print(e1.isNotEmpty); // false
print(e2 is String); // false
bool e3 = true;
List e4 = [1, 2, 3, if (e3) 4]; // [1, 2, 3, 4]
e3 = false;
List e5 = [1, 2, 3, if (e3) 5]; // [1, 2, 3]
Dart循环语句:
for循环
forEach循环(void返回值类型)
for in 循环
map循环(返回值新数组)
while循环
do while循环
List f1 = [1, 2, 3, 4, 5];
List f2 = [1, for (dynamic i in f1) i + 1]; // [1, 2, 3, 4, 5, 6]
/*
原理
for (dynamic i in f1) {
f2.add(i + 1);
}
*/
导入库需要部分
import '' show ;
隐藏库不需要部分
import '' hide ;
as 库重命名
import '' as http;
懒加载库
import '' deferred as http;
List有序的列表
List常用属性和方法:
length 列表长度
reversed 列表翻转
add(el) 列表末尾添加(void返回值类型)
addAll([el]) 拼接数组(void返回值类型)
indexOf(el,index = 0) 返回查找的元素索引或者-1
remove(el) 根据具体值删除(返回值true或者false)
removeAt(index) 根据索引删除(返回值删除的元素)
fillRange(index,indexend,el) 根据索引修改元素(void返回值类型)
insert(index,el) 指定位置插入(void返回值类型)
insertAll(index,List) 指定位置拼接列表(void返回值类型)
List g1 = [
1,
'1',
true,
{'c': 1},
[1]
];
print(g1.length);
print(g1.reversed); // ([1], {c: 1}, true, 1, 1)
g1.add(2);
g1.addAll([3]);
g1.addAll({3});
g1.indexOf(1, 0);
g1.remove([1]);
g1.removeAt(c1.length - 1);
g1.fillRange(0, 1, [124]);
g1.insert(0, [0]);
g1.insertAll(0, [123456]);
Set没有顺序不能重复的集合
常见属性和方法:
length 集合长度
first 返回集合首个元素
last 返回集合末尾元素
add(el) 集合末尾添加(void返回值类型)
addAll({el}) 拼接集合(void返回值类型)
remove(el) 根据具体值删除(返回值true或者false)
clear() 清除集合
contains 查找元素(返回值布尔类型)
containsAll 查找集合(返回值布尔类型)
Set h2 = {};
h2.add('name'); // {name}
h2.addAll([1, 2, 3]); // {name, 1, 2, 3}
h2.addAll({1, 2, 3}); // {name, 1, 2, 3}
print(h2.first); // name
print(h2.last); // 3
print(h2.remove('name')); // true
print(h2.contains(1)); // true
print(h2.containsAll({1, 2, 3})); // true
print(h2.containsAll([1, 2, 3])); // true
h2.clear(); // {}
Maps无序的键值对,键不可重复,值可以多次重复
常见属性和方法:
length 映射长度
keys 获取所有key
values 获取所有value
containsKey(key) 查找key(返回值布尔类型)
containsValue(value) 查找value(返回值布尔类型)
putIfAbsent(key,fn) 根据key,查找value并返回,没找到,则插入给定的key,value并返回插入的value
remove(key) 根据key删除key,value(返回删除的value)
clear() 清空映射
update(key,fn,ifAbsent) 根据key更新value并返回value,找不到key,调用ifAbsent函数,添加key,value并返回value
updateAll(fn) 遍历所有key并更新value
addAll() 拼接映射(void返回值类型)
Map i3 = {};
i3['name'] = '张三'; // 添加键值对
i3['age'] = 18; // 添加键值对
print(i3.containsKey('name')); // true
print(i3.containsValue('张三')); // true
print(i3.putIfAbsent('name', () => {'name': '李四'})); // 张三 {name: 张三, age: 18}
print(i3.putIfAbsent('lis',() => {'name': '李四'})); // {name: 李四}, {name: 张三, age: 18, lis: {name: 李四}}
print(i3.remove('age')); // 18
i3.update('sex', (val) => val = '男',ifAbsent: () => '女'); // 女, {name: 张三, age: 18, sex: 女}
print(i3.update('age', (value) => value = 20)); // 20
i3.updateAll((key, val) => {key = 1, key = 2, key = 3}); // {name: {1, 2, 3}, age: {1, 2, 3}}
i3.clear(); // {}
where(fn):过滤符合条件的元素(返回值是符合条件的元素)
any(fn):有符合条件的元素(返回值是布尔值)
every(fn):全部符合条件的元素(返回值是布尔值)
reduce(fn):把元素两两挑出来,执行函数。(返回值是操作的结果)
函数返回值类型 函数名(形参){…return} 函数名(实参)
/* 必选参数 */
int j1(int age,String name,) {
print(name);
return age;
}
j1(18, '张三');
/* 可选参数[age 有初始化值(可传可不传),className 允许为null值(可传可不传)] */
void j2(String name, [int age = 12, String? className]) {
print(name); // 李四
print(age); // 12
print(className); // null
}
j2('李四');
/* 命名参数{age 允许为null值(可传可不传),className 不允许为null值(必须传值),sex 有初始花值(可传可不传)} */
void j3(String name, {int? age, required String className, String sex = '男'}) {
print(name); // 王五
print(age); // null
print(className); // 大四
print(sex); // 男
}
j3('王五', className: '大四');
/* 高阶函数 */
void j4(fn) {
fn();
}
j4(j3);
/* 带参数高阶函数 */
void j5(void Function(String a, {int? b, double? c}) foo) {}
typedef Calculate = int Function(String a, {int b, double c}); // 函数签名(推荐写法)
void j5(Calculate calc) {calc('a');}
j5((a, {b = 1, c}) {});
/* 立即执行函数(自执行函数) */
(() {})(); // 推荐这种写法
(() {}());
/* 匿名函数,闭包,箭头函数(只能执行一条语句) */
Function j6() {
return () {
return () => print('箭头函数');
};
}
Function j7 = j6();
类(封装,继承,多态),抽象类,常量类,普通类
abstract
关键字定义抽象类,没有方法体的方法是抽象方法,抽象类不能实例化默认构造函数,可以实例化工厂构造函数,抽象类可以当接口,也可以当父类,Dart中接口很奇怪,所有类都可以当接口,implements 关键字实现接口,推荐使用抽象类当接口。
extends: 继承
子类继承父类普通的成员(属性和方法),不继承构造函数(默认和命名)
父类默认构造函数(有参数)需要 super
关键字传参数命名构造函数需要 super
调用,子类可以重写父类方法(方法形参类型和个数必须一样,方法返回值类型可以不同)
父类是抽象类子类是普通类必须实现父类所有抽象方法
多态:
允许将子类类型的指针赋值给父类类型的指针。
子类的实例赋值给父类的引用(Animal e = Dog()😉
父类定义一个方法,不去实现,让他的子类去实现(子类实现父类抽象方法)。
// class.dart文件
abstract class Person {
/* static 关键字实现静态成员(属性和方法),静态方法不能访问非静态成员,非静态方法可以访问静态成员,只能通过类自身访问 */
static late String name;
static int? age;
static String sex = '男';
static void run() {}
/* 抽象方法 */
eat();
/* 普通成员 */
late String hobby; // 延迟初始化
String? occupation; // 可以为空
String career = '计算机'; // 初始化值
void speak(int a, String b) {}
/* 私有成员 */
late int _a;
bool? _b;
final String _c = '私有属性';
void _d() {}
/* 默认构造函数(简写) : this.cry(occupation, a)函数重定向 */
Person(String occupation, String a) : this.cry(occupation, a);
/* 工厂构造函数 */
factory Person.foo() {
return Person
.foo(); // 因为是抽象类,所以只能这么写-_-!懒得写子类,抽象类可以实例化工厂构造函数(看dart源码),不能实例化普通构造函数。
}
/* 命名构造函数和默认构造函数不同,实例化不会自动执行。this.hobby = hobby :occupation = '程序员' 调用cry构造函数时默认初始化 */
Person.cry(this.occupation, String a) : hobby = '飞盘' {
speak(1, '1');
}
/* 命名构造函数 可选参数 */
Person.smile(this.occupation, String a, [String? b, String c = '1'])
: hobby = b ?? '足球'; /* 可选参数c */
/* 命名构造函数 命名参数 */
Person.play(
this.occupation,
String a, {
required String b,
/* required 必须传值 */
String c = '1',
});
/* get修饰符(不能接受参数) */
get secret {
return '$_a $_b $_c';
}
/* set修饰符(只能有一个参数) */
set amend(val) {
_a = val;
_d();
}
}
// main.dart
/* 普通类继承抽象类,必须实现抽象类方法 */
class Man extends Person {
/* Man(String name) : super(name); */
Man(super.name); // 两种写法
// 注解 实现抽象类方法
eat() {
throw UnimplementedError();
}
// 注解 按需重写父类方法(形参类型和数量必须一样,方法返回值类型可以不同)
String speak(int a, String b) {
super.speak(a, b); // 调用父类方法
return 'a';
}
}
/* 抽象类继承抽象类,不用实现父类抽象方法 */
abstract class Woman extends Person {
Woman(super.occupation);
}
implements:
实现接口,必须实现接口和接口继承的父类的所有普通成员,get修饰符,set修饰符,抽象方法
/* 实现接口,必须实现接口和接口继承的父类的所有普通成员,get修饰符,set修饰符,抽象方法 */
class Child implements Man, Woman {
late String career;
late String hobby;
String? occupation;
set amend(val) {}
eat() {}
get secret {}
String speak(int a, String b) {
return '实现接口';
}
}
mixin混入
void main() {
A a = A();
a.eat();
a.run();
}
mixin Animal {
void run() {}
}
mixin Flsh {
void eat() {}
}
class A with Animal, Flsh {}
枚举
void main() {
print(Animal.values);
}
enum Animal { eat, run, speak }