以通用方式管理特质实例消费者



让我们想象我有以下基本特质和案例类

sealed trait BaseTrait
case class Foo(x: Integer = 1) extends BaseTrait
case class Bar(x: String = "abc") extends 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())发生。我已经尝试了一些解决方案来解决此问题并实现所需的行为:

  • 最简单的方法是将适当的*Processor.process与匹配案例内的适当基础实例一起调用,这似乎无视以某种通用方式处理它们的全部点
  • 使用basemodel和基本处理器中的抽象类型,一只手摆脱了basemodel中有点不需要的类型参数,但编译器的投诉仍然有效,我无法弄清楚是否有可能使它能够工作<</li>
  • 从基本模型中摆脱类型的参数和相反,只需在处理器中铸造一个类型以获取适当的类型,但是显式类型的铸造也不是我真正希望的

喜欢:

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])
}

我想一个人也可以以某种方式说服编译器,两种类型(func参数p的T的T和T的T)是等效的,但这似乎也是一个过高的杀伤力(而且我也不确定它如何确定它是如何的可以完成)。

所以我的问题是:是否有可能在这里尝试实现的目标(以统一的方式管理处理器 每个处理器都以某种简单的方式知道其特定类型的基础属性)?我缺少一个更好的模型吗?

更新

根据蒂姆的答案,使控制器隐含地解决了问题,但是,如果您想在一个类中定义控制器 在其接口上具有" 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,一个用于栏):

找不到参数处理器的隐式值:基本处理器[foo]
方法的论点不足

有办法解决吗?我当然可以曝光控制器,以便可以隐式地通过,但是我宁愿不这样做。

您可以通过制作处理器implicit并将其作为额外的参数传递给func

来创建一个简单的类型。
implicit val fooProcessor = new FooProcessor(new FooModel)
implicit val barProcessor = new BarProcessor(new BarModel)
def func[T <: BaseTrait](p: T)(implicit processor: BaseProcessor[T]) =
  processor.process(p)

如果将Foo传递给func,它将在其上调用FooProcessor.process,如果将Bar传递给func,它将在其上调用BarProcessor

最新更新