在下面的代码中,我在下面的“问题”行中收到了上述错误。我的问题是,是否可以为z设置变量声明,以便可以为x或y分配。我的解决方法是consumeProduce方法,我真的不想要。感谢您的投入!
package org.rest.rest
trait Common
case class A() extends Common
case class B() extends Common
trait Producer[T <: Common] {
def produce(name: String): T = ???
}
trait Consumer[T <: Common] {
def consume(t: T): Unit = { }
}
class ProducerConsumer[T <: Common] extends Producer[T] with Consumer[T] {
// don't really want this method
def consumeProduce(name: String): Unit =
consume(produce(name))
}
object DemoMI {
val x = new ProducerConsumer[A]
x.consume(x.produce("abc"))
val y = new ProducerConsumer[B]
y.consume(y.produce("abc"))
val z: ProducerConsumer[_] = x // what type declaration for z is possible here?
z.consume(z.produce("abc")) // problem
z.consumeProduce("abc") // works
}
答案 0 :(得分:1)
问题是Scala编译不知道z.consume
采用z.produce
生成的内容。
您可以使用抽象类型成员来解决此问题:
trait Producer {
type T <: Common
def produce(name: String): T = ???
}
trait Consumer {
type T <: Common
def consume(t: T): Unit = { }
}
trait ProducerConsumer extends Producer with Consumer
object DemoMI {
val x = new ProducerConsumer {
type T = A
// definitions of consume and produce
}
val z: ProducerConsumer = x
z.consume(z.produce("abc"))
}
抽象类型成员提升了所谓的路径依赖类型的概念。在上面的示例中,z.produce(...)
的类型为z.T
。另一方面,z.consume(...)
采用z.T
类型的值。虽然编译器不知道所涉及的具体类型,但它知道两种方法都具有兼容的类型,因此很乐意编译。
答案 1 :(得分:0)
是的,@ gzm0有解决方案。我确实尝试过抽象类型成员,但无法使它们与参数化特征的行为不同。我现在能够添加的进一步改进是将效果结合起来:
trait ProducerConsumer extends Producer with Consumer
abstract class AbstractProducerConsumer[TT <: Common] extends ProducerConsumer {
type T = TT
}
val x = new AbstractProducerConsumer[A] {}
x.consume(x.produce("abc"))
val y = new AbstractProducerConsumer[B] {}
y.consume(y.produce("abc"))
val z1: ProducerConsumer = x
z1.consume(z1.produce("abc"))
val z2: ProducerConsumer = y
z2.consume(z2.produce("abc"))