Scala中Trait/抽象类无法初始化ClassTag的解决方案咨询
Scala Aggregatable Trait的ClassTag初始化解决方案
现有代码
Aggregatable Trait
trait Aggregatable[Command] { protected[aggregator] type ActorReply protected[aggregator] val actorReplyClassTag: ClassTag[ActorReply] ... // 其他实现代码 }
AsyncWorker抽象类
abstract class AsyncWorker[Request, Reply] extends Aggregatable[AsyncWorkerRequest[Request, Reply]] { override final type ActorReply = AsyncWorkerReply[Request, Reply] override protected val actorReplyClassTag: ClassTag[AsyncWorkerReply[Request, Reply]] = ??? ... // 其他实现代码 }
具体实现类
class SiteCategoriesExtractorWorker extends AsyncWorker[SiteCategoriesRequest, SiteCategoriesReply]
问题与约束
当前无法正确初始化actorReplyClassTag,解决方案需满足:
SiteCategoriesExtractorWorker无需感知actorReplyClassTag的存在ActorReply类型在aggregator包中通过asInstanceOf[ActorReply]方式使用actorReplyClassTag需兼容Akka的messageAdapter方法- 优先保留
Aggregatable为trait而非抽象类
备注:正通过反射对Aggregatable接口执行通用聚合操作。
可行解决方案
方案1:利用隐式ClassTag自动推导
修改AsyncWorker抽象类,依赖Scala编译器的隐式推导能力自动生成ClassTag,无需具体实现类做任何额外处理:
import scala.reflect.ClassTag trait Aggregatable[Command] { protected[aggregator] type ActorReply protected[aggregator] val actorReplyClassTag: ClassTag[ActorReply] ... // 其他实现代码 } abstract class AsyncWorker[Request, Reply] extends Aggregatable[AsyncWorkerRequest[Request, Reply]] { override final type ActorReply = AsyncWorkerReply[Request, Reply] // 编译器会根据具体Request/Reply类型自动推导ClassTag override protected[aggregator] val actorReplyClassTag: ClassTag[ActorReply] = implicitly[ClassTag[AsyncWorkerReply[Request, Reply]]] ... // 其他实现代码 } // 具体实现类无需修改,编译器自动处理ClassTag初始化 class SiteCategoriesExtractorWorker extends AsyncWorker[SiteCategoriesRequest, SiteCategoriesReply]
方案2:Aux模式增强类型关联(反射场景更友好)
如果需要在反射场景中更清晰地关联类型信息,可使用Aux模式扩展trait:
import scala.reflect.ClassTag trait Aggregatable[Command] { protected[aggregator] type ActorReply protected[aggregator] val actorReplyClassTag: ClassTag[ActorReply] ... // 其他实现代码 } // 定义Aux类型别名,明确关联Command、ActorReply和ClassTag object Aggregatable { type Aux[Command, AR] = Aggregatable[Command] { type ActorReply = AR } } abstract class AsyncWorker[Request, Reply](implicit ct: ClassTag[AsyncWorkerReply[Request, Reply]]) extends Aggregatable.Aux[AsyncWorkerRequest[Request, Reply], AsyncWorkerReply[Request, Reply]] { override protected[aggregator] val actorReplyClassTag: ClassTag[ActorReply] = ct ... // 其他实现代码 } class SiteCategoriesExtractorWorker extends AsyncWorker[SiteCategoriesRequest, SiteCategoriesReply]
方案合规性验证
- 具体实现类无感知:
SiteCategoriesExtractorWorker无需添加任何与actorReplyClassTag相关的代码 - 类型转换兼容:
aggregator包中asInstanceOf[ActorReply]的类型转换逻辑不受影响 - Akka API兼容:
actorReplyClassTag为稳定的val实例,完全满足messageAdapter对ClassTag的要求 - Trait保留:
Aggregatable始终保持为trait,未改为抽象类
内容的提问来源于stack exchange,提问作者Zvi Mints
相关产品推荐
相关产品推荐

