Flutter访客管理插件visitor的使用
Flutter访客管理插件visitor的使用
visitor 插件简介
visitor
是一个基于 Dart 的库,它可以根据类和类型定义上的注解生成代码,这些代码实现了访问者模式(Visitor Pattern)。通过这种方式,可以方便地处理具有复杂结构的对象树。
例如,在一个 func.dart
文件中,你可以定义如下代码:
import 'package:visitor/visitor.dart';
part 'func.g.dart';
@Visitor(name: "Func")
class _Func<R> {}
@VisitorBranch(of: _Func)
typedef _Func$Supplier<T, R> = T Function();
@VisitorBranch(of: _Func)
typedef _Func$UnaryOperator<T, R> = T Function(R x);
@VisitorBranch(of: _Func)
typedef _Func$BinaryOperator<T, R> = T Function(R x, R y);
这将生成如下的代码到 func.g.dart
文件中:
abstract class Func<R> {
const factory Func.supplier() = _OnSupplierFunc;
const factory Func.unaryOperator(R x) = _OnUnaryOperatorFunc;
const factory Func.binaryOperator(R x, R y) = _OnBinaryOperatorFunc;
const Func._();
T choose<T>({
required _Func$Supplier<T, R> onSupplier,
required _Func$UnaryOperator<T, R> onUnaryOperator,
required _Func$BinaryOperator<T, R> onBinaryOperator,
});
}
class _OnSupplierFunc<R> extends Func<R> {
const _OnSupplierFunc() : super._();
@override
T choose<T>({
required _Func$Supplier<T, R> onSupplier,
required _Func$UnaryOperator<T, R> onUnaryOperator,
required _Func$BinaryOperator<T, R> onBinaryOperator,
}) {
return onSupplier();
}
}
class _OnUnaryOperatorFunc<R> extends Func<R> {
final R x;
const _OnUnaryOperatorFunc(this.x) : super._();
@override
T choose<T>({
required _Func$Supplier<T, R> onSupplier,
required _Func$UnaryOperator<T, R> onUnaryOperator,
required _Func$BinaryOperator<T, R> onBinaryOperator,
}) {
return onUnaryOperator(x);
}
}
class _OnBinaryOperatorFunc<R> extends Func<R> {
final R x;
final R y;
const _OnBinaryOperatorFunc(this.x, this.y) : super._();
@override
T choose<T>({
required _Func$Supplier<T, R> onSupplier,
required _Func$UnaryOperator<T, R> onUnaryOperator,
required _Func$BinaryOperator<T, R> onBinaryOperator,
}) {
return onBinaryOperator(x, y);
}
}
你可以在以下代码中使用生成的代码:
int apply(Func<int> func) {
final int result = func.choose<int>(
onSupplier: () => 1,
onUnaryOperator: (x) => 2 * x,
onBinaryOperator: (x, y) => x + y,
);
return result;
}
void main() {
Func<int> f;
f = Func.supplier();
print(apply(f));
// 输出: 1
f = Func.unaryOperator(2);
print(apply(f));
// 输出: 4
f = Func.binaryOperator(3, 5);
print(apply(f));
// 输出: 8
}
或者,你可以将其视为类似于 Kotlin 中密封类的概念。
特性
- 支持泛型。
- 支持递归参数类型。
- 支持命名参数和可选参数。
开始使用
在你的 pubspec.yaml
文件中添加此依赖作为开发依赖项。
使用方法
该库导出了两个注解:Visitor
和 VisitorBranch
。
Visitor 注解
Visitor
注解用于类。类名必须以一个或多个下划线开头(例如 _Example
)。
@Visitor()
class _Example {}
VisitorBranch 注解
VisitorBranch
注解用于类型定义(typedef)。它接收一个必需的参数 of
,应为它的访问者类型。
@VisitorBranch(of: _Example)
每个带有 VisitorBranch
注解的 typedef 将成为其相应访问者的分支,并且:
- 必须别名为一个函数,该函数可以有零个或多个参数;
- 必须有一个返回类型
T
的参数类型; - 可以有任意名称,但建议以
_$
开头,以避免外部引用。如果有多个访问者在一个文件中声明,则为了避免名称冲突,其名称应为_
+ 访问者的大写驼峰命名法名称 +$
+ 分支的大写驼峰命名法名称。
@VisitorBranch(of: _Example)
typedef _$FirstBranch<T> = T Function(int);
在当前文件的导入部分下方添加一个部分声明。例如,如果文件名为 file.dart
:
part 'file.g.dart';
在添加了 Visitor
、其 VisitorBranch
和部分声明之后,在项目的根目录下运行以下命令:
dart run build_runner build
# 或者,如果你正在使用 Flutter
flutter pub run build_runner build
生成的代码将被添加到部分声明中描述的文件中。以下是更改的内容:
- 生成访问者的名称将是类名去掉第一个下划线(例如
Example
)。 - 访问者中的生成工厂方法的名称将是每个分支的小写驼峰命名法(例如
firstBranch
)。 - 访问者的生成子类的名称将是每个分支的大写驼峰命名法,前缀为
_On
并后缀于大写驼峰命名法的访问者名称(例如_OnFirstBranchExample
)。 - 访问者的回调名称将是每个分支的大写驼峰命名法,前缀为
on
(例如onFirstBranch
)。
abstract class Example implements _Example {
const factory Example.firstBranch(int p0) = _OnFirstBranchExample;
const Example._();
T choose<T>({
required T Function(int) onFirstBranch,
});
}
class _OnFirstBranchExample extends Example {
final int p0;
const _OnFirstBranchExample(int p0) : super._();
T choose<T>({
required T Function(int) onFirstBranch,
}) {
return onFirstBranch(p0);
}
}
对于带有 VisitorBranch
注解的 typedef,linter 可能会产生一个未使用的元素警告。为了避免这种情况,可以在文件顶部添加以下内容:
// ignore_for_file: unused_element
示例
你可以在 example/lib/visitor_example.dart
文件中看到用法。
在 example/lib/examples
中:
expression.dart
显示了递归参数类型的用法;diff_change.dart
显示了命名参数的用法;loading_state.dart
显示了泛型的用法。
示例代码
以下是一个完整的示例代码:
import 'package:visitor_example/examples/diff_change.dart';
import 'package:visitor_example/examples/expression.dart';
import 'package:visitor_example/examples/loading_state.dart';
void runExpressionExample() {
int evaluate(Expression expression) {
return expression.choose(
onConstant: (v) => v,
onSum: (e0, e1) => evaluate(e0) + evaluate(e1),
onZero: () => 0,
);
}
print(evaluate(loadExpression("21 + 0 + 4")));
// 输出: 25
}
void runDiffChangeExample() {
final List<DiffChange> changes = loadChanges(
["area", "beer", null, "city", null, "edge"],
["acid", "beer", null, null, "deep", "else"],
);
for (DiffChange change in changes) {
print(change.choose<String>(
onAdded: (v) => "+ $v",
onDeleted: (v) => "- $v",
onUnchanged: (v) => " $v",
onChanged: ({required v0, required v1}) => "* $v1 (was $v0)",
));
}
// 输出:
// * acid (was area)
// beer
// - city
// + deep
// * else (was edge)
}
Future<void> runLoadingStateExample() async {
final Stream<LoadingState> stream = loadStates();
await for (LoadingState state in stream) {
print(state.choose(
onWaiting: () => "waiting",
onError: (e) => "error ($e)",
onValue: (v) => "value ($v)",
onDone: () => "done",
));
}
// 输出:
// waiting
// value (1)
// value (2)
// error (Bad state: i == 3)
// value (4)
// value (5)
// done
}
void main() async {
runExpressionExample();
runDiffChangeExample();
await runLoadingStateExample();
}
更多关于Flutter访客管理插件visitor的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html