向 Dart 中的函数添加带有泛型参数的 void 回调
Adding a void callback with a generic parameter to a function in Dart
我想做什么
给定以下节点:
class Node<T> {
Node(this.value);
T value;
Node? child;
// TODO: add `visit` method
@override
String toString() => value.toString();
}
我想添加一个 visit
方法,该方法将递归地对每个节点及其子节点的值执行一些操作。然后我可以做这样的事情:
void main() {
final root = Node(1);
root.child = Node(2);
root.child!.child = Node(3);
// one of these
root.visit(print);
root.visit((value) => print(value));
// 1
// 2
// 3
}
天真的解决方案
如果我执行以下操作,它会起作用:
void visit(Function action) {
action(value);
child?.visit(action);
}
天真的解决方案存在问题
然而,这个语句中的value
被推断为dynamic
:
root.visit((value) => print(value));
我想将其推断为与节点的通用 T
类型相同的类型。
此外,编译器允许以下操作,这会导致 运行 时间崩溃:
root.visit(() => 42);
我希望这是一个编译时错误。
尝试的解决方案 1
如果我将 visit
更改为以下内容:
void visit(Function(T value) action) {
action(value);
child?.visit(action(value));
}
编译时一切看起来都很好:
root.visit(print); // OK
root.visit((value) => print(value)); // OK
root.visit(() => 42); // error
但是如果我注释掉最后一个和 运行 前两个代码中的任何一个,那么我将得到以下 运行 时间错误:
Unhandled exception:
type 'Null' is not a subtype of type '(dynamic) => dynamic'
我不太清楚那是什么意思。
尝试的解决方案 2
已添加 void
:
void visit(void Function(T value) action) {
action(value);
child?.visit(action(value)); // error
}
This expression has a type of 'void' so its value can't be used.
Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void. (dartuse_of_void_result)
尝试的解决方案 3
这只是暗中刺杀:
void visit(void Function<T>(T value) action) {
action(value);
child?.visit(action);
}
visit
方法似乎可以编译,但像以前一样调用它会出现编译时错误:
root.visit(print); // error
root.visit((value) => print(value)); // error
错误读取:
The argument type 'void Function(Object?)' can't be assigned to the parameter type 'void Function(T)'. (dartargument_type_not_assignable)
相关问题
这些问题似乎相关,但我不知道如何从中提取解决方案:
- How to create a generic method in Dart?
- Dart: Type error when overrding generic function in abstract class
我该如何解决这个问题?
感谢@jamesdlin 在评论中解决问题。
您需要将 child
的通用类型设置为 Node<T>
。然后您可以将方法签名指定为 void visit(Function(T value) action)
并将 action
本身传递给 child.
完整示例如下:
void main() {
final root = Node(1);
root.child = Node(2);
root.child!.child = Node(3);
// one of these
root.visit(print);
root.visit((value) => print(value)); // value inferred as int
// root.visit(() => 42); // compile-time error
// 1
// 2
// 3
}
class Node<T> {
Node(this.value);
T value;
Node<T>? child;
void visit(Function(T value) action) {
action(value);
child?.visit(action);
}
@override
String toString() => value.toString();
}
我想做什么
给定以下节点:
class Node<T> {
Node(this.value);
T value;
Node? child;
// TODO: add `visit` method
@override
String toString() => value.toString();
}
我想添加一个 visit
方法,该方法将递归地对每个节点及其子节点的值执行一些操作。然后我可以做这样的事情:
void main() {
final root = Node(1);
root.child = Node(2);
root.child!.child = Node(3);
// one of these
root.visit(print);
root.visit((value) => print(value));
// 1
// 2
// 3
}
天真的解决方案
如果我执行以下操作,它会起作用:
void visit(Function action) {
action(value);
child?.visit(action);
}
天真的解决方案存在问题
然而,这个语句中的value
被推断为dynamic
:
root.visit((value) => print(value));
我想将其推断为与节点的通用 T
类型相同的类型。
此外,编译器允许以下操作,这会导致 运行 时间崩溃:
root.visit(() => 42);
我希望这是一个编译时错误。
尝试的解决方案 1
如果我将 visit
更改为以下内容:
void visit(Function(T value) action) {
action(value);
child?.visit(action(value));
}
编译时一切看起来都很好:
root.visit(print); // OK
root.visit((value) => print(value)); // OK
root.visit(() => 42); // error
但是如果我注释掉最后一个和 运行 前两个代码中的任何一个,那么我将得到以下 运行 时间错误:
Unhandled exception:
type 'Null' is not a subtype of type '(dynamic) => dynamic'
我不太清楚那是什么意思。
尝试的解决方案 2
已添加 void
:
void visit(void Function(T value) action) {
action(value);
child?.visit(action(value)); // error
}
This expression has a type of 'void' so its value can't be used. Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void. (dartuse_of_void_result)
尝试的解决方案 3
这只是暗中刺杀:
void visit(void Function<T>(T value) action) {
action(value);
child?.visit(action);
}
visit
方法似乎可以编译,但像以前一样调用它会出现编译时错误:
root.visit(print); // error
root.visit((value) => print(value)); // error
错误读取:
The argument type 'void Function(Object?)' can't be assigned to the parameter type 'void Function(T)'. (dartargument_type_not_assignable)
相关问题
这些问题似乎相关,但我不知道如何从中提取解决方案:
- How to create a generic method in Dart?
- Dart: Type error when overrding generic function in abstract class
我该如何解决这个问题?
感谢@jamesdlin 在评论中解决问题。
您需要将 child
的通用类型设置为 Node<T>
。然后您可以将方法签名指定为 void visit(Function(T value) action)
并将 action
本身传递给 child.
完整示例如下:
void main() {
final root = Node(1);
root.child = Node(2);
root.child!.child = Node(3);
// one of these
root.visit(print);
root.visit((value) => print(value)); // value inferred as int
// root.visit(() => 42); // compile-time error
// 1
// 2
// 3
}
class Node<T> {
Node(this.value);
T value;
Node<T>? child;
void visit(Function(T value) action) {
action(value);
child?.visit(action);
}
@override
String toString() => value.toString();
}