flutter基础-dart语法2

2024/3/15 flutterdart

🌙 类型

类似于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);
}

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() {
  // 局部变量推断
  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 {}
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

🌙 类型转换

  • 隐式类型转换:在Dart中,编译器会尽可能地进行隐式类型转换,即在不会导致数据丢失的情况下自动将数据类型转换为所需的类型。

  • 例如,将一个整数赋值给一个浮点数变量,Dart会自动将整数转换为浮点数。


int a = 5;
double b = a; // 隐式类型转换,将整数转换为浮点数 

1
2
3
4
  • 显式类型转换:有时候需要手动进行类型转换,可以使用类型转换操作符来实现。

使用as关键字进行类型转换,如果类型不匹配会抛出异常。


dynamic value = 42;
int intValue = value as int; // 显式类型转换,将dynamic类型转换为int类型
1
2
3

使用is和as结合进行安全类型转换,如果类型不匹配会返回null。


dynamic value = '42';
int? intValue = value is int ? value as int : null; // 安全类型转换,将dynamic类型转换为int类型,如果转换失败返回null
1
2
3

使用构造函数进行类型转换:某些数据类型之间可以通过构造函数相互转换,例如将字符串转换为整数。


String str = '42';
int intValue = int.parse(str); // 使用int.parse方法将字符串转换为整数
1
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
}

1
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
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

通过使用类型守卫,可以在Dart中更安全地处理对象的类型,避免在运行时出现类型不匹配的问题。

🌙 泛型

在Dart语言中,**泛型(Generics)**是一种在编程中使用类型参数来创建可复用代码的技术。通过泛型,可以编写更加通用和灵活的代码,同时提高代码的类型安全性。以下是关于Dart语言泛型的一些基本概念:

泛型类(Generic Class):可以定义一个类,其中的某些成员的类型可以是参数化的。通过在类名后面使用来声明泛型类,其中T是类型参数。

class Box<T> {
  T value;

  Box(this.value);
}

void main() {
  var box = Box<int>(10); // 创建一个存储整数的Box对象
  print(box.value); // 输出: 10
}
1
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'); // 调用泛型方法,传入字符串类型参数
}
1
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');
  }
}
1
2
3
4
5
6
7
8
9
10
11

🌙 并发

  • Dart是单线程模型语言,也就没有了所谓的主线程/子线程之分
  • 只要Dart函数开始执行,它将会执行到这个函数结束,也就是说Dart的函数不会被其他Dart代码打断
  • 在Dart语言中,可以通过使用异步编程来实现并发操作。Dart提供了一套强大的异步编程模型,其中包括Futureasync和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...'); // 这行代码会先执行
}

1
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');
  });
}
1
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');
  });
}
1
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
1
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();
}

1
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();
}

1
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();
}

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

🌙 包的使用和开发

在Dart中,您可以使用pub工具来管理包和开发包。

🌙 使用包

中文站点 (opens new window)

  • 添加包依赖:在您的项目的pubspec.yaml文件中添加包依赖。例如,如果要添加http包的依赖,可以这样写:
dependencies:
  http: ^0.13.3
1
2
  • 获取依赖:在命令行中运行pub get命令,以获取项目所需的依赖包。

🌙 开发包

  • 创建包:使用pub工具创建一个新的Dart包。在命令行中运行命令:pub create <package_name>

  • 开发包:在创建的包目录中开发您的包,包括添加代码、编写文档等。

  • 测试包:可以编写单元测试来确保包是否正常工作。

  • 发布包:如果希望将包分享给其他开发者,可以将包发布到Dart包管理器网站上。

🌙 使用开发包

在项目中使用开发包:在您的项目的pubspec.yaml文件中添加对您的开发包的依赖。例如:


dependencies:
  my_package:
    path: /path/to/your/package

1
2
3
4
5

获取依赖:运行pub get命令,以获取项目所需的依赖包,包括开发包。