由于最后一行,以下内容无法编译:
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
的类型是什么,但是当我从IO
中提取Wrapper
的实例时,我需要能够访问它(未显示的代码)。
如何更改“示例1”以进行编译,同时以对客户端代码可见的方式保留Out参数。
(如果这个表述不清楚,请评论)
答案 0 :(得分:3)
您只需对代码进行两次小修改。
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
方法的返回类型更改为w.type
。这样就保留了完整类型的w
(包括所有改进)。如果您将Wrapper[T]
写为返回类型,并且要求Wrapper[T]
T
等于IO[String]
,您将获得Wrapper[IO[String]]
以及所有额外知识,例如{ {1}}将丢失。
第二:在{type Out = String}
中,您说val io: IO[String] = wrap.unwrap
是io
。同样,所有额外的知识都会丢失。所以让编译器推断出IO[String]
的类型。
另一件事:如果您不希望io
在Wrapper
中变为协变,则可以省略方差注释并更改T
方法。
apply
如果你调用trait Wrapper[T] {
def unwrap: T
}
object Wrapper {
def apply[T](implicit w: Wrapper[_ <: T]): w.type = w
}
,那么编译器仍然知道它必须寻找 IO[String]
的子类型。由于Wrapper.apply[IO[String]]
是IO[String]{type out = String}
的子类型,因此它们不相等。
答案 1 :(得分:1)
不清楚你想要实现的目标,但这能解决你的问题吗? (注意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
类型施加任何限制。
用户是否定义了自己的解码器,在这种情况下,您不关心In
和Out
,或者您有一些基本的解码器并且您提供它,例如:IO [Int,String],IO [Int,Boolean]等