带泛型的Dart typedef引发子类型错误问题求助
问题描述
运行代码时抛出类型不匹配错误:
Unhandled exception:
type '(OnBadAir) => bool' is not a subtype of type '(Event) => bool'
#0 Fork._dispatch
typedef.dart:33
#1 main
这段代码提取自fsm2包,由于事件队列需处理不同类型的事件,无法做强类型标注,因此遇到了typedef逆变导致的类型问题。需解决如何向事件队列传递可被调度器处理的condition。
完整复现代码:
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(); }
问题分析
错误根源在于:
Fork类中的td成员未指定泛型,被隐式推断为TransitionDefinition<Event>,但实际传入的是TransitionDefinition<OnBadAir>。- Dart中函数类型是逆变的:
bool Function(OnBadAir)无法赋值给bool Function(Event)——后者要求能接收任意Event类型参数,而前者只能处理OnBadAir子类。
解决方案
方案1:对齐泛型约束(单一事件类型场景)
修改Fork类,让td的泛型与Fork的泛型E保持一致,并安全转换队列中的事件类型:
class Fork<E extends Event> { Fork(this.td); // 指定td的泛型为E,与Fork泛型对齐 TransitionDefinition<E> td; final _eventQueue = <_QueuedEvent>[]; void queue(E event) { _eventQueue.add(_QueuedEvent(event)); } Future<void> _dispatch() async { assert(_eventQueue.isNotEmpty, 'The event queue is in an invalid state'); final queuedEvent = _eventQueue.first; // 队列中的事件都是通过queue传入的E类型,转换安全 final event = queuedEvent.event as E; if (td.condition(event)) { print('it worked'); } } }
此方案类型安全性高,适合Fork实例仅处理单一事件类型的场景。
方案2:调整条件函数的类型适配(多事件类型场景)
如果队列需要兼容多种事件类型,可修改GuardCondition的定义,让函数先判断事件类型再处理:
// 修改typedef,参数统一为Event类型 typedef GuardCondition<E extends Event> = bool Function(Event event); class TransitionDefinition<E extends Event> { TransitionDefinition({required this.condition}); final GuardCondition<E> condition; } // 使用时在条件函数内先做类型判断 void main() async { final fork = Fork<OnBadAir>( TransitionDefinition<OnBadAir>(condition: (event) { if (event is OnBadAir) { return event.quality < 10; } return false; })) ..queue(OnBadAir(10)); await fork._dispatch(); }
此方案灵活性更高,适合队列中存在多种Event子类的场景。
内容的提问来源于stack exchange,提问作者Brett Sutton
相关产品推荐
相关产品推荐

