0%

解锁 Flutter 的神秘关键字,快来一探究竟!

Flutter 中常用到或者见到的关键字做一个收集和介绍。

1.showhideas

import 文件的时候,使用 show 关键字可以仅导入库中的某个特定部分,而不是整个库。在你只需要库中的一部分内容的时候非常有用,避免不必要的命名冲突,也能明确哪些部分被使用。而 hide 关键字可以导入库的大部分内容,但排除特定的部分。这在你需要库的几乎所有内容,但想要避免特定部分的命名冲突时非常有用。as 则为导入的库起个别名,避免类名冲突。

如:providerflutter_riverpod 都提供类似的功能用于状态管理,并且有一些类名是相同的,其中 Provider 类本身,在两个插件库中都有。还有 flutter_intlintl 也有相似类名 DateFormat

4701716695159_.pic.png

Provider 类为例,使用 showhide 关键字来解决命名冲突。

1
2
import 'package:provider/provider.dart' show ChangeNotifierProvider, Consumer;
import 'package:flutter_riverpod/flutter_riverpod.dart' hide ChangeNotifierProvider, Consumer;

也可以给冲突的类名起个别名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import 'package:provider/provider.dart' as provider;
import 'package:flutter_riverpod/flutter_riverpod.dart' as riverpod;

class _ProviderWidgetState<T extends ChangeNotifier>
extends State<ProviderWidget<T>> {
@override
Widget build(BuildContext context) {
return provider.ChangeNotifierProvider<T>(
create: (_) => widget.model,
child: provider.Consumer<T>(
builder: widget.builder,
child: widget.child,
),
);
}
}

2.partpart of

partpart ofDart 语言中用于管理分割文件的关键字。如我们常使用 @freezed 注解生成 xxx.freezed.dart 文件,下面以 HomeEvent 类来举例:

home_event.dart

1
2
3
4
5
6
7
8
9
10
11
12
// 表示 home_event.freezed.dart 是 home_event.dart 文件的一部分, 
// 通常用于将大的类或功能拆分成多个文件
part 'home_event.freezed.dart';

abstract class HomeEvent extends BaseBlocEvent {
const HomeEvent();
}

@freezed
class HomePageInitiated extends HomeEvent with _$HomePageInitiated {
const factory HomePageInitiated() = _HomePageInitiated;
}

freezed 生成 home_event.freezed.dart
4711716706149_.pic.png

上图中的 part of 'home_event.dart'; 也是表示 home_event.freezed.darthome_event.dart 文件的一部分。part of 关键字后面跟着所属文件,其作用就是将多个文件组合在一起,使它们共同构成一个完整的 Dart 文件。

3.deferred

做延迟加载的,将库的加载推迟到第一次访问该库时才进行,而不是在应用程序启动时就加载。对于减少应用启动时间和减小应用包大小非常有用。

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
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' deferred as mylib;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Deferred Loading Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
loadLibrary(context);
},
child: Text('Load Library'),
),
),
),
);
}

Future<void> loadLibrary(BuildContext context) async {
await mylib.loadLibrary(); // 加载延迟加载库
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DeferredPage()),
);
}
}

class DeferredPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Deferred Page'),
),
body: Center(
child: FutureBuilder(
future: mylib.myFunction(), // 使用延迟加载库中的函数
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else {
return Text(snapshot.data.toString());
}
},
),
),
);
}
}

这里的 mylib 是一个延迟加载的库。 deferred as mylib 关键字将延迟加载库导入为 mylib。在 main 函数中,我们通过 mylib.loadLibrary() 方法加载延迟加载库。加载完成后,我们可以像使用普通库一样使用 mylib 中的类、函数。

当然延迟加载库的实现需要去配置 Android 原生的 build.gradle 文件和 Flutterpubspec.yaml 文件等操作,还对 Dart 版本有要求,具体细节大家感兴趣的话可以尝试实现一下。

这几个是和类、文件导入相关相关的,下面介绍几个和 dart 语法相关的关键字。

4.typedef

使用 typedef 关键字为现有类型创建别名(类型别名 Type Alias),其常用于函数类型,可以简化其定义和使用。

1
2
3
4
5
6
7
8
9
10
typedef Compare<T> = int Function(T a, T b);

int compareInt(int a, int b) {
return a - b;
}

void main() {
Compare<int> comp = compareInt;
print(comp(3, 2)); // 输出 1
}

还常用于给类型起一个一眼就能看得懂的名字,提高代码可读性。

1
2
3
4
5
6
7
8
9
10
11
typedef UserInfo = Map<String, String>;

void printUserInfo(UserInfo user) {
//这里使用 UserInfo 比直接是 Map 更好理解吧
print('Name: ${user['name']}, Email: ${user['email']}');
}

void main() {
UserInfo user = {'name': 'John Doe', 'email': 'john.doe@example.com'};
printUserInfo(user);
}

5.yield

yield 关键字用于在 Dart 中创建生成器函数。生成器函数是一种特殊的函数,它可以在需要时逐步生成一系列值,而不是一次性生成并返回所有值,通常在迭代器中(for...in)使用。下面以生成斐波那契数列算法为例来看看 yield 关键字的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Iterable<int> fibonacciSequence(int count) sync* {
int a = 0;
int b = 1;
for (int i = 0; i < count; i++) {
yield a; // 生成斐波那契数列中的当前值
int temp = a + b;
a = b;
b = temp;
}
}

void main() {
// 生成前 10 个值
Iterable<int> fibonacciNumbers = fibonacciSequence(10);
for (int number in fibonacciNumbers) {
print(number);
}
}
///输出结果:0 1 1 2 3 5 8 13 21 34

函数 fibonacciSequence 就是一个生成指定数量的斐波那契数列的生成器函数。在每次迭代中使用yield a 生成斐波那契数列中的当前值,并把这个当前值 a 返回给调用者,然后这个生成过程先暂停下来,等待下次调用(下一次 for 循环),再去执行生成斐波那契数列中的当前值,就是这么个意思。

6.mixin

mixin 我们平时见得很多,就是 Dart 用于解决多继承的问题,使用 mixin 可以将一组通用的方法和属性封装在一个独立的类中,然后在需要的类中混入这个 mixin ,从而使得这些类都具有相同的行为。本质上就是通过组合类的方式来重用代码的机制。

mixin 的特点:一个类可以混入多个 mixin ,不能被实例化,只包含方法和属性的定义,没有状态或构造函数。

如我们比较常用的 LogMixin 类,通常将 LogMixin 混入到项目 bloc 的基类 BaseBloc,方便在业务逻辑中打印和调试。

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
mixin LogMixin on Object {
void logD(String message, {DateTime? time}) {
Log.d(message, name: runtimeType.toString(), time: time);
}
}

abstract class BaseBloc<E extends BaseBlocEvent, S extends BaseBlocState>
extends Bloc<E, S> with LogMixin {
BaseBloc(S initialState) : super(initialState);
}

@Injectable()
class HomeBloc extends BaseBloc<HomeEvent, HomeState> {
HomeBloc(this._repository) : super(HomeState()) {
on<HomePageInitiated>(
_onHomePageInitiated
);
}

final Repository _repository;

FutureOr<void> _onHomePageInitiated(
HomePageInitiated event, Emitter<HomeState> emit) async {
// 直接使用 LogMixin 的 logD 函数
logD("HomePageInitiated: $event");
}
}

以上关键字介绍都是基于个人理解,总结的或许不够全面和准确,那么在日常开发中有遇到哪些你理解起来比较费劲的关键字呢?欢迎留言交流,感谢您的阅读!