如何通过正确包装类来线程化类型?

A Q*_*ker 3 scala

trait Thing {
  type Out
  def get: Out
}

case class Wrapper(t: Thing) extends Thing {
  type Out = t.Out
  override def get = t.get
}

def hey(t: Thing): t.Out = Wrapper(t).get
Run Code Online (Sandbox Code Playgroud)

这给了我一个类型错误,虽然它显然是类型安全的.我想知道如何向编译器正确地证明这是安全的而不必进行强制转换.

有任何想法吗?

Tra*_*own 5

如果你真的,真的不想打开一个类型参数Wrapper,你可以推出自己的假案例类,而不太健忘apply:

trait Thing {
  type Out
  def get: Out
}

abstract class Wrapper(t: Thing) extends Thing

object Wrapper {
  def apply(t: Thing): Wrapper { type Out = t.Out } =
    new Wrapper(t) {
      type Out = t.Out
      def get: Out = t.get
    }
}

def hey(t0: Thing): t0.Out = Wrapper(t0: Thing { type Out = t0.Out }).get
Run Code Online (Sandbox Code Playgroud)

(在现实生活中,你也想要定义案例类给你的所有其他东西 - 有用的平等等)

问题是,在Wrapper.apply定义case类时自动生成的只返回a Wrapper,这意味着编译器丢失了有关它的所有静态信息Out.如果您自己编写apply,则可以通过使返回类型为指定的返回类型来保留该信息Out.

为了证明它有效:

scala> val myThing = new Thing {
     |   type Out = String
     |   def get = "foo"
     | }
myThing: Thing{type Out = String} = $anon$1@5e265ba4

scala> hey(myThing)
res0: myThing.Out = foo

scala> val foo: String = hey(myThing)
foo: String = foo
Run Code Online (Sandbox Code Playgroud)

因此编译器能够跟踪事实OutString一直存在的.