注意:我已经完全重写了这个问题,因为我知道有一段完整的代码可以重现这个问题。
下面的代码失败:
Unhandled exception:
type '(OnBadAir) => bool' is not a subtype of type '(Event) => bool'
#0 Fork._dispatch
typedef.dart:33
#1 main
这是从fsm 2包中提取的。
因为'dispatch'事件正在处理一个具有不同事件类型的事件队列,所以dispatch事件不能被类型化,然后我们遇到了typedef是逆变的问题(如@Lrn所指出的)。
因此,问题是如何将“条件”传递到调度程序可以处理的事件队列中?
import 'dart:async';
class Event {}
class OnBadAir extends Event {
OnBadAir(this.quality);
int quality;
}
typedef GuardCondition<E extends Event> = bool Function(E event);
class _QueuedEvent {
_QueuedEvent(this.event);
Event event;
}
class Fork<E extends Event> {
Fork(this.td);
TransitionDefinition td;
final _eventQueue = <_QueuedEvent>[];
void queue(E event) {
_eventQueue.add(_QueuedEvent(event));
}
/// dequeue the next event and transition it.
Future<void> _dispatch() async {
assert(_eventQueue.isNotEmpty, 'The event queue is in an invalid state');
final event = _eventQueue.first;
/// crashes here.
if (td.condition(event.event)) {
print('it worked');
}
}
}
class TransitionDefinition<E extends Event> {
TransitionDefinition({required this.condition});
final GuardCondition<E> condition;
}
void main() async {
final fork = Fork<OnBadAir>(
TransitionDefinition<OnBadAir>(condition: (e) => e.quality < 10))
..queue(OnBadAir(10));
await fork._dispatch();
}
1条答案
按热度按时间cbjzeqam1#
我的猜测是你已经声明了
TransitionDefinition
如下:td
实际上是一个TransitionDefinition<OnBadAir>
类型的示例。但是,由于某种原因,
_evaluateConditions(td, OnBadAir(5));
将<Event>
的类型参数推断为_evaluateConditions
,因此_evaluateConditions
中的td
具有TransitionDefinition<Event>
的静态类型(TransitionDefinition<E>
,其中E
动态绑定到Event
)。这意味着当你得到表达式
td.condition
时,代码需要一个bool Function(Event)
。由于类的类型参数在condition
中出现 contravariantly,但类泛型是协变的,因此编译器不能假设运行时值是bool Function(Event)
。所以它插入一个检查。检查失败,因为实际类型是
bool Function(OnBadAir)
,而不是bool Function(Event)
。前者不能用与后者相同的参数调用,这是我们对子类型的要求的一部分。这就是为什么你得到一个运行时错误。如果您可以使用
_evaluateConditions<OnBadAir>(td, OnBadAir(5));
来执行调用,则错误可能会消失。一般来说,在函数类型的字段或返回类型中使用类的类型参数作为 parameter(在逆变位置)类型是不安全的。如果将这样的类示例向上强制转换为超类型,并尝试访问该字段,则可能会引发。为了您自己的保护,由于该值不是合理的,因此它的类型不会是该表达式的静态预期类型的子类型。