具有类型成员的隐式包装特征无法编译
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
类型施加任何限制。
用户是否定义了它自己的解码器,在那种情况下你不关心In
和Out
,或者你有一些基本的解码器并提供它,例如: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
.
的类型
另一件事:如果您不希望 Wrapper
在 T
中是协变的,您可以不使用方差注释并更改 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]
的子类型,所以它们不相等。
由于最后一行,以下内容无法编译:
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
类型施加任何限制。
用户是否定义了它自己的解码器,在那种情况下你不关心In
和Out
,或者你有一些基本的解码器并提供它,例如: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
.
另一件事:如果您不希望 Wrapper
在 T
中是协变的,您可以不使用方差注释并更改 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]
的子类型,所以它们不相等。