🌙 类型
类似于typescript和java语法
🌙 使用 .runtimeType
打印类型
void main() {
var a = 'hello';
var b = 1;
var c = false;
var d = 3.14;
Map<String, int> e = {'a': 1, 'b': 2};
Record f = ('first', one: 1, two: '2', 'last');
List<int> g = [1, 2, 3, 4];
Set<dynamic> h = {1, 2, 3, 'a', false, 3.14};
Point p1 = Point(1, 2);
Point3D p2 = new Point3D(1, 2, 3);
print(a.runtimeType); // String
print(b.runtimeType); // int
print(c.runtimeType); // bool
print(d.runtimeType); // double
print(e.runtimeType); // _Map<String, int>
print(f.runtimeType); // (String, String, {int one, String two})
print(g.runtimeType); // List<int>
print(h.runtimeType); // _Set<dynamic>
print(p1.runtimeType); // Point
print(p2.runtimeType); // Point3D
}
class Point {
final double x;
final double y;
Point(this.x, this.y);
}
class Point3D extends Point {
final double z;
Point3D(super.x, super.y, this.z);
}
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() {
// 局部变量推断
var number = 42; // Dart会自动推断number为int类型
var name = 'Alice'; // Dart会自动推断name为String类型
var x = 3; // x is inferred as an int.
// x = 4.0;
num y = 3; // A num can be double or int.
y = 4.0;
// 参数类型推断
// Inferred as if you wrote <int>[].
List<int> listOfInt = [];
// Inferred as if you wrote <double>[3.0].
var listOfDouble = [3.0];
// Inferred as Iterable<int>.
var ints = listOfDouble.map((x) => x.toInt());
// 替换类型
List<Animal> animals = [Dog()];
List<Cat> cats = animals as List<Cat>;
// 类型断言
dynamic value = 42;
var intValue = value as int; // 使用as关键字进行类型断言,将value转换为int类型
dynamic value = '42';
var intValue = value as int?; // 使用as?关键字进行安全的类型断言,如果转换失败会返回null
}
class Animal {}
class Cat extends Animal {}
class Dog extends Animal {}
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
🌙 类型转换
隐式类型转换:在Dart中,编译器会尽可能地进行隐式类型转换,即在不会导致数据丢失的情况下自动将数据类型转换为所需的类型。
例如,将一个整数赋值给一个浮点数变量,Dart会自动将整数转换为浮点数。
int a = 5;
double b = a; // 隐式类型转换,将整数转换为浮点数
2
3
4
- 显式类型转换:有时候需要手动进行类型转换,可以使用类型转换操作符来实现。
使用as关键字进行类型转换,如果类型不匹配会抛出异常。
dynamic value = 42;
int intValue = value as int; // 显式类型转换,将dynamic类型转换为int类型
2
3
使用is和as结合进行安全类型转换,如果类型不匹配会返回null。
dynamic value = '42';
int? intValue = value is int ? value as int : null; // 安全类型转换,将dynamic类型转换为int类型,如果转换失败返回null
2
3
使用构造函数进行类型转换:某些数据类型之间可以通过构造函数相互转换,例如将字符串转换为整数。
String str = '42';
int intValue = int.parse(str); // 使用int.parse方法将字符串转换为整数
2
3
🌙 类型守卫
在Dart语言中,类型守卫(Type Guard)是一种用于在运行时检查对象类型的技术,以确保在进行类型转换或类型操作时不会导致运行时错误。在Dart中,可以 使用is和as关键字来实现类型守卫。
使用is关键字进行类型守卫的示例:
void printLength(dynamic value) {
if (value is String) {
print('Length of the string: ${value.length}');
} else if (value is List) {
print('Length of the list: ${value.length}');
} else {
print('Unsupported type');
}
}
void main() {
printLength('Hello'); // 输出: Length of the string: 5
printLength([1, 2, 3]); // 输出: Length of the list: 3
printLength(42); // 输出: Unsupported type
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
除了使用is关键字进行类型守卫外,还可以结合使用as关键字进行安全类型转换,以确保在转换时不会出现异常情况:
void processValue(dynamic value) {
if (value is int) {
int intValue = value as int; // 安全类型转换
print('Integer value: $intValue');
} else {
print('Not an integer');
}
}
void main() {
processValue(42); // 输出: Integer value: 42
processValue('Hello'); // 输出: Not an integer
}
2
3
4
5
6
7
8
9
10
11
12
13
14
通过使用类型守卫,可以在Dart中更安全地处理对象的类型,避免在运行时出现类型不匹配的问题。
🌙 泛型
在Dart语言中,**泛型(Generics)**是一种在编程中使用类型参数来创建可复用代码的技术。通过泛型,可以编写更加通用和灵活的代码,同时提高代码的类型安全性。以下是关于Dart语言泛型的一些基本概念:
泛型类(Generic Class):可以定义一个类,其中的某些成员的类型可以是参数化的。通过在类名后面使用
class Box<T> {
T value;
Box(this.value);
}
void main() {
var box = Box<int>(10); // 创建一个存储整数的Box对象
print(box.value); // 输出: 10
}
2
3
4
5
6
7
8
9
10
泛型方法(Generic Method):可以在方法声明中使用类型参数,使得方法可以接受不同类型的参数。
T getValue<T>(T value) {
return value;
}
void main() {
int intValue = getValue<int>(10); // 调用泛型方法,传入整数类型参数
String stringValue = getValue<String>('Hello'); // 调用泛型方法,传入字符串类型参数
}
2
3
4
5
6
7
8
泛型接口(Generic Interface):可以定义一个接口,其中的方法可以接受泛型类型参数。
abstract class Repository<T> {
Future<T> getById(int id);
}
class UserRepository implements Repository<String> {
Future<String> getById(int id) {
// 实现获取用户信息的逻辑
return Future.value('User $id');
}
}
2
3
4
5
6
7
8
9
10
11
🌙 并发
- Dart是单线程模型语言,也就没有了所谓的主线程/子线程之分
- 只要Dart函数开始执行,它将会执行到这个函数结束,也就是说Dart的函数不会被其他Dart代码打断
- 在Dart语言中,可以通过使用异步编程来实现并发操作。Dart提供了一套强大的异步编程模型,其中包括
Future
、async和await
关键字,以及Stream和Future
的组合操作等,来支持并发编程。
1.Future和async/await:使用Future、async和await来实现异步操作。Future表示一个异步操作的结果,async用于定义一个异步函数,await用于等待异步操作完成。
Future<void> fetchData() async {
print('Fetching data...');
await Future.delayed(Duration(seconds: 2)); // 模拟异步操作
print('Data fetched');
}
void main() {
fetchData();
print('Main function continues...'); // 这行代码会先执行
}
2
3
4
5
6
7
8
9
10
11
2.Stream:使用Stream来处理数据序列,可以通过订阅Stream来监听数据的变化
Stream是一个抽象类,用于表示一序列异步数据的源。它是一种产生连续事件的方式,可以生成数据事件或者错误事件,以及流结束时的完成事件。
Stream 的好处是处理过程中内存占用较小。举个例子:在读取file文件数据的时候, Future 只能一次获取异步数据。而 Stream 能多次异步获得的数据。如果当文件比较大,明显Futrue占用的时间更久,这样子就会导内存占用过大。
Stream<int> countStream(int n) async* {
for (int i = 1; i <= n; i++) {
yield i;
await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
}
}
void main() {
countStream(5).listen((data) {
print('Count: $data');
});
}
2
3
4
5
6
7
8
9
10
11
12
3.Future的组合操作:可以使用Future的组合操作,如Future.wait来等待多个异步操作完成。
Future<void> fetchData1() async {
await Future.delayed(Duration(seconds: 2)); // 模拟异步操作
print('Data 1 fetched');
}
Future<void> fetchData2() async {
await Future.delayed(Duration(seconds: 3)); // 模拟异步操作
print('Data 2 fetched');
}
void main() {
Future.wait([fetchData1(), fetchData2()]).then((_) {
print('All data fetched');
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
通过以上方式,可以在Dart中实现并发操作,处理异步任务并管理多个并发任务的执行顺序。
🌙 网络请求
在Dart中进行网络请求通常涉及到异步操作,可以使用http包或者dart:io中的HttpClient来实现。下面分别介绍两种方式:
🌙 1.使用http包进行网络请求:
- 首先,在
pubspec.yaml
文件中添加http
包的依赖:
dependencies:
http: ^0.13.3
2
- 然后,可以通过
http
包来发起网络请求:
import 'package:http/http.dart' as http;
Future<void> fetchData() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/1');
var response = await http.get(url);
if (response.statusCode == 200) {
print('Response: ${response.body}');
} else {
print('Failed to fetch data. Status code: ${response.statusCode}');
}
}
void main() {
fetchData();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
http包
是flutter中实现网络请求的一种方式;flutter开发中还可以使用
Dio包
, 功能更加强大;
🌙 2.使用HttpClient进行网络请求
dart:io
中的HttpClient
可以用于发起网络请求,需要注意的是,**HttpClient在Flutter中不可用,只能在Dart命令行应用程序中使用
**。
import 'dart:io';
Future<void> fetchData() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/1');
var httpClient = HttpClient();
var request = await httpClient.getUrl(url);
var response = await request.close();
var responseBody = await response.transform(utf8.decoder).join();
print('Response: $responseBody');
httpClient.close();
}
void main() {
fetchData();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
🌙 使用Future.wait
来处理多个网络请求
import 'package:http/http.dart' as http;
Future<void> fetchData(int postId) async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts/$postId');
var response = await http.get(url);
if (response.statusCode == 200) {
print('Response for post $postId: ${response.body}');
} else {
print('Failed to fetch data for post $postId. Status code: ${response.statusCode}');
}
}
Future<void> fetchMultipleData() async {
List<Future> futures = [];
for (int i = 1; i <= 3; i++) {
futures.add(fetchData(i));
}
await Future.wait(futures);
print('All requests completed');
}
void main() {
fetchMultipleData();
}
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
🌙 包的使用和开发
在Dart中,您可以使用pub
工具来管理包和开发包。
🌙 使用包
- 查找包:在Dart包管理器网站 (opens new window)上查找您需要的包。
- 添加包依赖:在您的项目的
pubspec.yaml
文件中添加包依赖。例如,如果要添加http包的依赖,可以这样写:
dependencies:
http: ^0.13.3
2
- 获取依赖:在命令行中运行
pub get
命令,以获取项目所需的依赖包。
🌙 开发包
创建包:使用
pub
工具创建一个新的Dart包。在命令行中运行命令:pub create <package_name>
开发包:在创建的包目录中开发您的包,包括添加代码、编写文档等。
测试包:可以编写单元测试来确保包是否正常工作。
发布包:如果希望将包分享给其他开发者,可以将包发布到Dart包管理器网站上。
🌙 使用开发包
在项目中使用开发包:在您的项目的pubspec.yaml文件中添加对您的开发包的依赖。例如:
dependencies:
my_package:
path: /path/to/your/package
2
3
4
5
获取依赖:运行pub get
命令,以获取项目所需的依赖包,包括开发包。