具有类型成员的隐式包装特征无法编译

Implicitly wrapped trait with type member does not compile

由于最后一行,以下内容无法编译:

object ImplicitWrappedTraitWithType {

  trait Wrapper[+T] {
    def unwrap: T
  }

  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }

  trait IO[In] {
    type Out

    def out: Out
  }

  implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] {
    override def unwrap: IO[In] {type Out = String} = new IO[In] {
      override type Out = String
      override val out: Out = "yeah"
    }
  }

  val wrap = Wrapper[IO[String]]
  val io: IO[String] = wrap.unwrap
  val out: String = io.out //actual type: unwrap.Out
}

我该怎么做才能让编译器相信 val out 是一个 String


预编辑 - 忽略此

示例 1 - 这不会编译:

object ImplicitWrappedTraitWithType {
  class Wrapper[T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = null

//client code
  Wrapper[IO[String]]
}

示例 2 - 而这样做:

object ImplicitWrappedTraitWithType {
  class Wrapper[T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In]] = null

//client code
  Wrapper[IO[String]]
}

在客户端代码中,我不知道 Out 的类型是什么,但是当我从 [=17] 中提取 IO 的实例时,我需要能够访问它=](未显示的代码)。

必须如何更改 'Example 1' 才能编译,同时以客户端代码可见的方式保留 Out 参数。

(这个表述不清楚的请评论)

不清楚您要实现的目标,但这能解决您的问题吗? (注意 Wrapper 中的 -T)

object ImplicitWrappedTraitWithType {
  class Wrapper[-T]
  object Wrapper {
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w
  }
  trait IO[In] {
    type Out
  }
  implicit def decoder[In]: Wrapper[IO[In]] = null


}
import ImplicitWrappedTraitWithType._

trait IOString[In] extends IO[In] { 
  type Out = String
}
//client code
Wrapper[IOString[Int]]

在尝试为其寻找隐式解码器时,我不会对 Out 类型施加任何限制。

用户是否定义了它自己的解码器,在那种情况下你不关心InOut,或者你有一些基本的解码器并提供它,例如:IO[Int , String], IO[Int, Boolean], 等等

您只需对代码进行两次小的修改。

trait Wrapper[+T] {
  def unwrap: T
}

object Wrapper {
  def apply[T](implicit w: Wrapper[T]): w.type = w
}

trait IO[In] {
  type Out

  def out: Out
}

implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] {
  override def unwrap: IO[In] {type Out = String} = new IO[In] {
    override type Out = String
    override val out: Out = "yeah"
  }
}

val wrap = Wrapper[IO[String]]
val io = wrap.unwrap
val out: String = io.out

最重要的是将apply方法的return类型改为w.type。这样 w 的完整类型(包括所有细化)将被保留。如果您将 Wrapper[T] 写为 return 类型,并且您要求 Wrapper[T] for T 等于 IO[String],您将得到 Wrapper[IO[String]] 和所有{type Out = String} 等额外知识将丢失。

其次:在val io: IO[String] = wrap.unwrap中你说io是一个IO[String]。同样,所有额外的知识都丢失了。所以让编译器推断 io.

的类型

另一件事:如果您不希望 WrapperT 中是协变的,您可以不使用方差注释并更改 apply 方法。

trait Wrapper[T] {
  def unwrap: T
}

object Wrapper {
  def apply[T](implicit w: Wrapper[_ <: T]): w.type = w
}

这样编译器仍然知道如果您调用 Wrapper.apply[IO[String]] 它必须寻找 IO[String] 的子类型。因为 IO[String]{type out = String}IO[String] 的子类型,所以它们不相等。