flutter学习

Dart基础

特点

  • 强类型语言,静态类型。面向对象

  • JIT&AOT

    JIT: 即时编译,开发期间,更快编译,更快重载。

    AOT: 在发布时可以通过 AOT 生成高效的机器码以保证应用性能。而 JavaScript 则不具有这个能力

  • 类型安全和空安全

数据类型

  • 数字、类型转换
1
2
3
4
5
6
7
8
9
10
11
12
13
//num 是数字类型的父类,两个子类 int double
_numType(){
num num1 = -1.0;
num num2 = 2;
int int1 = 1; //只能是整数
double d1 = 1.234; //双精度的浮点数
print("num: $num1 num2: $num2 int1:$int1 double:$d1");

//常用方法
print(num1.abs()); //绝对值
print(num1.toInt()); //转换成int
print(num2.toDouble()); //转换成浮点
}
  • 字符串类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
_stringType() {
//定义
String str1 = "双引号", str2 = '单引号';
String str3 = "str1: $str1 str2:$str2";
String str6 = "ABC的风格";
print(str3);
//常用方法
print(str6.substring(0,3)); //截取
print(str6.indexOf('ABC')); //查找位置
str6.startsWith('A');
str6.contains('B');
str6.split('A');
str6.replaceAll('BC', '');
}
  • 布尔类型,强类型检查
1
2
3
4
5
6
_boolType() {
bool success = true, fail = false;
print('success $success fail:$fail');
print(success || fail);
print(success && fail);
}
  • 集合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//List 类型
_listType() {
List list = [];
//初始化添加元素 动态类型
List list2 = [1, 2, 3, '集合'];
//添加泛型
List<String> list3 = ['A', 'B', 'C'];
print(list2);
print(list3);

list3.add('D');
list2.addAll(list3);
print(list2);
print(list3);

//生产元素方式 length: 3
List list4 = List.generate(3, (index) => index * 2);
print(list4);

//遍历方式
for (int i = 0; i < list4.length; i++) {
print(list4[i]);
}

for (var i in list4) {
print(i);
}

list4.forEach((element) {
print(element);
});

//常用方法
list4.remove('value');
list4.insert(1, 'element');
list4.sublist(1);
list4.indexOf(2);
}


//Map 类型
_mapType() {
//key和value相关联的对象
//key和valuekey是任何类型
//key是唯一的,如果key重复,后面添加的key会被替换

//初始化
Map names = {"xiaoming":'小明','xiaomi':'小米'};
print(names);
Map ages = {};
ages['xiaoming'] = 16;
ages['xiaohong'] = 18;
print(ages);

//遍历
ages.forEach((key, value) {
print('key: $key value:$value');
});

//通过遍历一个map 来生成另外一个map
Map ages2 = ages.map((key, value){
return MapEntry(key, value + 1);
});
print(ages2);

for(var key in ages2.keys){
print('key: $key value: ${ages2[key]}');
}

Map<String,int> ages3 = {};
ages3['age1'] = 1;
ages3['age2'] = 2;
print(ages3);

//常用方法
ages3.keys;
ages3.values;
ages3.remove('age1');
ages3.containsKey('age1');
}

dynamic var Object 的使用和区别

  • dynamic 是所有dart对象的基础类型,在大多数情况下不使用它。
    通过它定义的变量会关闭类型检查,这意味着
1
2
dynamic x = 'hello';
x.foo();

这段代码静态类型检查不会报错,但是运行会crash,因为x并没有提供foo()方法。

  • var 是一个关键字,意思是‘我不关心这里的类型是什么’,系统会自动推荐类型runtimeType。
  • Object 是dart对象的基类,当定义 Object o = xx ,系统会默认o是一个对象,可以调用Object提供的方法,如:toString(),hashCode()。但是尝试调用o.foo() 静态类型检查会报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
_tips() {
//动态类型
dynamic x = 'hello';
// x.foo(); //运行时会报错
print(x.runtimeType);
print(x);
x = 123;
print(x);
print(x.runtimeType);

var a = 'world';
// a = 123; // 类型检查出错
print(a.runtimeType);

Object o1 = 'hellowe';
print(o1.runtimeType);
print(o1);
print(o1.toString());
}

函数/方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//方法的构成:
///返回值类型 + 方法名 + 参数
///返回值类型:可以省略,也可以为void或具体的类型
///方法名:匿名方法不需要方法名
///参数:参数类型和参数名,参数类型可以省略(可选参数和参数默认值)
int sum(int x, int y, {bool? isPrint = false}) {
if (isPrint ?? false) {
print('object');
}
return x + y;
}


class FunctionTest {
int _privateVariable = 10;

//实例方法:
//需要对象调用
int sum(int a, int b) {
return a + b;
}

//私有方法:
//私有方法和私有变量在 Dart 中通过在名称前加上下划线 _ 来定义
//私有成员只能在定义它们的类内部访问
//子类可以继承父类的私有成员,但不能在子类中直接访问这些私有成员

///私有成员的访问限制是在库(library)级别的,而不是类级别的。
// 在同一个 Dart 文件中,所有代码都属于同一个库,可以访问私有成员。
// 在不同文件中,私有成员只能在定义它们的库内访问,不能跨库访问。
void _learn() {
print('私有方法,类实例调用不了');
}


//匿名方法:
//没有名字的方法,lambda或者closure闭包
//可以把匿名方法赋值给一个变量,然后使用这个方法。
/***
* ([Type] param1[,...]){
* codebloc
* }
* 匿名方法中不需要用到的参数可以使用_
* (_){}
*/
void test() {
var list = ['1','2'];
list.forEach((element) {
print('$element');
});
}

//静态方法:
//类名.方法名
static int dosum(int v1,int v2) {
return v1 + v2;
}
}

void main() {
sum(2, 2, isPrint: true);

FunctionTest functionTest = new FunctionTest();
functionTest.sum(1, 1);
// functionTest._learn(); 报错
}

面向对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
void main() {
Person person = Person('junech', 23);
print(person.toString());

Student student = Student('北大', 'tom', 23);
print(student.toString());

Student student1 = Student.cover(student);
print('student1: ${student1.toString()}');

Student student2 = Student.stu(student);
print('student2: ${student2.toString()}');

Logger logger1 = Logger();
Logger logger2 = Logger();
print('logger1 == logger2 ${logger1 == logger2}');
}

//都继承自Object
class Person {
String? name;
int? age;

Person(this.name, this.age);

@override
String toString() {
return 'name: $name age:$age';
}
}

//构造方法初始化列表
class Student extends Person {
String? _school;
String? city;
String? county;
String? funName;

//为私有变量设置 get/set方法
String? get school => _school;

set school(String? value) {
_school = value;
}

//构造方法:
//this._school 初始化自有参数
//name,age 交给父类进行初始化
//city 为可选参数
//county 设为默认值
Student(this._school, String? name, int? age,
{this.city, this.county = 'china'})
: funName = '$county.$city',
super(name, age) {
//构造方法体不是必须的
}

//命名构造方法:
//类名 + . + 方法名
//通过命名构造方法可以为类实现多个构造方法
Student.cover(Student stu) : super(stu.name, stu.age) {
print('命名构造方法');
}

//命名工厂构造方法:
//factory 类名 . 方法名
//可以有返回值,而且不需要将类的final 变量作为参数,可以灵活获取类的对象
factory Student.stu(Student st) {
return Student(st._school, st.name, st.age);
}

@override
String toString() {
return 'name: $name age:$age school:$_school city:$city county:$county';
}
}

////////////////////////////////////////////////////////////////
//抽象类:
//1、不能实例化
//2、其作用用于定义接口
//3、抽象类中也有一些实现
abstract class Study {
void study();

void study2() {
print('抽象类');
}
}

//抽象类既可以继承也可以实现
//实现的时候必须是实现抽象类中所有方法
class StudyFlutter extends Study {
@override
void study() {}
}

class StudyDart implements Study {
@override
void study() {}

@override
void study2() {}
}
////////////////////////////////////////////////////////////////

//工厂构造方法
//单例
class Logger {
static Logger? _cache;

factory Logger() {
_cache ??= Logger._internal();
return _cache!;
}

//是一个私有构造函数,用于在类内部创建 Logger 实例
Logger._internal();
}

  • mixin使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// mixin的特点
//复用代码:mixin 提供了一种复用代码的方式,可以在多个类之间共享相同的行为。
// 避免多重继承的问题:Dart 不支持多重继承,但 mixin 提供了一种替代方式,可以让类拥有多重行为。
//灵活性:你可以将多个 mixin 混入一个类中,从而组合出多种行为。

mixin MyMixin {
// 可以定义属性
String get description => "This is a mixin";

// 可以定义方法
void mixinMethod() {
print('Method from MyMixin');
}
}

class MyBaseClass {
void baseMethod() {
print('Method from MyBaseClass');
}
}

class MyClass extends MyBaseClass with MyMixin {
void myMethod() {
print('Method from MyClass');
}
}

void main() {
var myObject = MyClass();
myObject.baseMethod(); // Method from MyBaseClass
myObject.mixinMethod(); // Method from MyMixin
print(myObject.description); // This is a mixin
myObject.myMethod(); // Method from MyClass
}

  • 泛型使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void main() {

Cache<String> cache = Cache();
cache.setItem('cache1', 'value1');
print(cache.getItem('cache1'));

Cache<int> cache1 = Cache();
cache1.setItem('cache2', 1009);
print(cache1.getItem('cache2'));
}

//泛型作用
//1、提供代码复用性,解决类、接口、方法的复用性,以及对不特定数据类型的支持
//2、类型检查的约束,List<String>

//泛型类
class Cache<T> {
final Map<String, T> _cache = {};

void setItem(String key, T value) {
_cache[key] = value;
}

T? getItem(String key) {
return _cache[key];
}
}

//类型约束 T extends Person
class Member<T extends Person> {
final T _person;

Member(this._person);

String fixedName(){
return '${_person.name}';
}
}

Dart 中的编程小技巧总结

  • Dart 提供了多个 null 安全操作符,可以帮助简化处理 null 值的代码:
1
2
3
4
5
6
7
8
9
10
11
12
/// ?? 操作符:用于提供默认值
String? name;
String displayName = name ?? 'Guest';

/// ??= 操作符:如果变量为 null,则赋值。
String? name;
name ??= 'Guest';

/// ?. 操作符:用于安全地调用可能为 null 的对象的方法或属性
String? name;
print(name?.toUpperCase());

  • 使用集合操作符简化列表和集合的操作
1
2
3
4
5
6
7
8
9
/// 扩展操作符 ... 和 ...?:
List<int> list1 = [1, 2, 3];
List<int> list2 = [4, 5, 6];
List<int> combinedList = [...list1, ...list2]; // [1, 2, 3, 4, 5, 6]

/// 集合字面量和条件元素:
bool addExtra = true;
List<int> numbers = [1, 2, 3, if (addExtra) 4]; // [1, 2, 3, 4]

  • 使用级联操作符 (..)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// 级联操作符可以让你在同一个对象上进行多次操作,而不需要重复引用对象:

class Builder {
int? value;
void increment() => value = (value ?? 0) + 1;
void reset() => value = 0;
}

void main() {
var builder = Builder()
..increment()
..increment()
..reset();
print(builder.value); // 0
}

  • 使用常量构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// 尽可能使用常量构造函数 (const) 来定义不可变对象,这样可以提高性能并减少内存开销:

class Point {
final int x;
final int y;
const Point(this.x, this.y);
}

const point1 = Point(1, 2);
const point2 = Point(1, 2);

void main() {
print(identical(point1, point2)); // true
}

  • 使用扩展方法
1
2
3
4
5
6
7
8
9
10
11
12
/// 扩展方法可以为现有类添加新的方法,而无需修改类本身:
extension NumberParsing on String {
int? toIntOrNull() {
return int.tryParse(this);
}
}

void main() {
print('123'.toIntOrNull()); // 123
print('abc'.toIntOrNull()); // null
}

  • 使用 as 和 is 进行类型检查和转换
1
2
3
4
5
6
7
8
9
10
11
/// 类型检查 is:
dynamic value = 'hello';
if (value is String) {
print('The value is a string');
}

/// 类型转换 as:
dynamic value = 'hello';
String str = value as String;
print(str.toUpperCase()); // HELLO

  • 使用解构赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// 虽然 Dart 没有直接支持解构赋值,但你可以使用 List 和 Map 来实现类似的效果:
/// 列表解构:
List<int> numbers = [1, 2, 3];
var [a, b, c] = numbers;
print(a); // 1
print(b); // 2
print(c); // 3

/// 映射解构:
Map<String, int> map = {'x': 1, 'y': 2};
var {'x': x, 'y': y} = map;
print(x); // 1
print(y); // 2

  • 使用 assert 进行调试
1
2
3
4
5
6
7
8
/// 在开发过程中,可以使用 assert 来确保某些条件为真。如果条件为假,程序会在调试模式下抛出异常:

void main(List<String> args) {
int age = 15;
assert(age >= 18, 'Age must be at least 18.');
print('Age is $age');
}

  • 使用 async 和 await 进行异步编程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// Dart 支持异步编程,使用 async 和 await 可以让你的代码更加简洁和易读:

Future<void> fetchData() async {
var data = await getDataFromServer();
print(data);
}

Future<String> getDataFromServer() async {
return Future.delayed(Duration(seconds: 2), () => "Server Data");
}

void main() {
fetchData();
}

  • 使用 late 延迟初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// 使用 late 关键字来延迟对象的初始化,直到第一次使用它:

class Example {
late String value = _computeValue();

String _computeValue() {
print('Computing value...');
return 'Hello, late!';
}
}

void main() {
var example = Example();
print(example.value); // Computing value... Hello, late!
}