【发布时间】:2019-05-20 22:27:59
【问题描述】:
假设我有以下基本特征和案例类
sealed trait BaseTrait
case class Foo(x: Integer = 1) extends BaseTrait
case class Bar(x: String = "abc") extends BaseTrait
我想为可以处理 BaseTrait 实例的类创建一个通用接口,如下所示
class FooProcessor(val model: FooModel) extends BaseProcessor[Foo] {
val v: Option[Foo] = model.baseVar
}
class BarProcessor(val model: BarModel) extends BaseProcessor[Bar] {
val v: Option[Bar] = model.baseVar
}
为此,我有以下特点
trait BaseModel[T <: BaseTrait] {
var baseVar: Option[T] = None
}
trait BaseProcessor[T <: BaseTrait] {
def model: BaseModel[T]
def process(x: T): Unit = model.baseVar = Option(x)
}
模型定义如下
class FooModel extends BaseModel[Foo]
class BarModel extends BaseModel[Bar]
现在让我们想象一下,我的应用中有以下处理器
val fooProcessor = new FooProcessor(new FooModel)
val barProcessor = new BarProcessor(new BarModel)
我想以某种通用的方式处理它们,像这样
def func[T <: BaseTrait](p: T) {
val c/*: BaseProcessor[_ >: Foo with Bar <: BaseTrait with Product with Serializable]*/ = p match {
case _: Foo => fooProcessor
case _: Bar => barProcessor
c.process(p)
}
编译器对最后一行不太满意,它说
类型不匹配;
发现:T
必需:_1
如果我理解正确,这基本上是编译器试图阻止 barProcessor.process(Foo()) 发生。我尝试了几种解决方案来解决这个问题并实现所需的行为:
- 解决此问题的最简单方法是在匹配案例中使用正确的 BaseTrait 实例调用正确的
*Processor.process,这似乎违背了以某种通用方式处理它们的全部意义 - 在 BaseModel 和 BaseProcessor 中使用抽象类型,一方面摆脱了 BaseModel 中有些不需要的类型参数,但编译器的抱怨仍然有效,我无法弄清楚是否有可能让它工作
- 摆脱 BaseModel 中的类型参数和约束,只需在处理器中进行类型转换以获得正确的类型,但显式类型转换也不是我真正希望的
像这样:
trait BaseModel {
var baseVar: Option[BaseTrait] = None
}
trait BaseProcessor[T <: BaseTrait] {
def model: BaseModel
def process(x: T): Unit = model.baseVar = Some(x)
def getBaseValue: T = model.baseVar.map(_.asInstanceOf[T])
}
我想人们也可以以某种方式让编译器相信这两种类型(处理器的 T 和 func 参数 p 的 T)是等价的,但这似乎也有点矫枉过正(而且我也不确定它是怎么做到的可以)。
所以我的问题如下:是否有可能以某种简单的方式完成我在这里想要实现的目标(以统一的方式管理处理器 + 每个处理器都知道其特定的 BaseTrait 类型)?有没有更好的模型我错过了?
更新
根据Tim's answer,使控制器隐式可以解决问题,但是,如果您想要一个定义控制器的类+在其接口上具有“func”,编译器似乎不再正确地解决隐式问题。所以如果我尝试做这样的事情
class ProcessorContainer {
implicit val fooProcessor = new FooProcessor(new FooModel)
implicit val barProcessor = new BarProcessor(new BarModel)
def func[T <: BaseTrait](p: T) = typedFunc(p)
private def typedFunc[T <: BaseTrait](p: T)(implicit processor: BaseProcessor[T]) =
processor.process(p)
}
class Test {
val processorContainer = new ProcessorContainer
processorContainer.func(Foo())
processorContainer.func(Bar())
}
我收到以下编译错误(一个用于 Foo,一个用于 Bar):
找不到参数处理器的隐含值:BaseProcessor[Foo]
方法参数不足
有没有办法解决这个问题?我当然可以公开控制器,以便可以隐式传递它们,但是我不想这样做。
【问题讨论】: