我在玩以下代码:
class A
class B
class C
trait Codecs[L] {
case class Codec[R](val code: L => R, val decode: R => L)
object Codec
def code[R](foo: L)(implicit codec: Codec[R]): R = codec.code(foo)
def decode[R](bar: R)(implicit codec: Codec[R]): L = codec.decode(bar)
}
object Codecs {
implicit object ACodecs extends Codecs[A] {
object Codec {
implicit val ab: Codec[B] = new Codec(_ => new B, _ => new A)
implicit val ac: Codec[C] = new Codec(_ => new C, _ => new A)
}
}
}
object test extends App {
val codecs = implicitly[Codecs[A]]
codecs.code[B](new A)
}
它将不会编译,因为编译器无法找到类型Codecs.Codec[B]
的隐式值。
据我了解,两个值ab
和ac
的类型为Acodecs.Codec[_]
(或类似的类型),这并不是编译器正在寻找的。我还知道,将案例类Codec[_]
及其同伴移到特征之外可以解决此问题(在使其具有2类参数之后)。如果需要隐式值,则编译器应在隐式范围内包括所需类型的伴随对象。我的问题是:
trait
的两个方法的签名(最好是更改隐式参数的类型签名)以进行编译?如何从特征Acodecs.Codec[_]
内部引用类型Codecs[_]
?就像,您如何在嵌套类型上执行此类型类操作?
是否存在某种模式或某种可以解决此类问题的东西?
答案 0 :(得分:2)
问题是您的类型绑定到特定实例,因为它是内部类。而且编译器不知道implicitly[Codecs[A]]
给出的实例与其在下一行隐式找到的实例完全相同。例如,如果您明确传递它:
codecs.code[B](new A)(Codecs.ACodecs.Codec.ab)
您收到以下错误消息:
type mismatch;
found : Codecs.ACodecs.Codec[B]
required: codecs.Codec[B]
因此,它认为封闭实例可能不同,类型也不同。
我从未真正看到过这种特定类型的隐式嵌套-即其中包含与路径相关的隐式类型类的隐式类型类。因此,我怀疑是否存在处理它的模式,并且实际上会对它提出建议。似乎过于复杂。这是我个人对待此案的方法:
case class Codec[L, R](val code: L => R, val decode: R => L)
trait Codecs[L] {
type LocalCodec[R] = Codec[L, R]
def code[R](foo: L)(implicit codec: LocalCodec[R]): R = codec.code(foo)
def decode[R](bar: R)(implicit codec: LocalCodec[R]): L = codec.decode(bar)
}
object Codecs {
implicit object ACodecs extends Codecs[A] {
implicit val ab: LocalCodec[B] = new LocalCodec(_ => new B, _ => new A)
implicit val ac: LocalCodec[C] = new LocalCodec(_ => new C, _ => new A)
}
}
object test extends App {
import Codecs.ACodecs._
val codecs = implicitly[Codecs[A]]
codecs.code[B](new A)
}
您仍然可以使用“半缩窄”类型的好处,但这只是类型别名,因此不存在路径依赖问题。