为什么 scala 的隐式查找会忽略嵌套 class 的伴生对象
why does scala's implicit lookup ignore companion object of nested class
我正在玩弄以下代码:
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[_]
(或类似的东西),这并不是编译器正在寻找的。我也知道将 case class Codec[_]
及其同伴移到特征之外可以解决问题(在使其采用 2 个类型参数之后)。如果需要隐式值,编译器应在隐式范围内包含所需类型的伴生对象。我的问题是:
- 如何将编译器指向依赖于路径的子类型,更具体地说:
- 是否可以更改
trait
的两个方法的签名(最好更改隐式参数的类型签名)以进行编译?如何从特征 Codecs[_]
内部引用类型 Acodecs.Codec[_]
?
比如,你如何在嵌套类型上做这种类型class的事情?
是否有处理此类问题的模式或东西?
问题是您的类型绑定到特定实例,因为它是内部 class。并且编译器不知道 implicitly[Codecs[A]]
给出的实例与它在下一行隐式找到的实例完全相同。例如,如果您显式传递它:
codecs.code[B](new A)(Codecs.ACodecs.Codec.ab)
您收到此错误消息:
type mismatch;
found : Codecs.ACodecs.Codec[B]
required: codecs.Codec[B]
因此它认为封闭的实例可能不同,因此类型不同。
我从未真正见过这种特定类型的隐式嵌套——即隐式类型class,其中包含路径相关的隐式类型classes。所以我怀疑是否存在处理它的模式,实际上我会建议不要这样做。这似乎过于复杂。以下是我个人如何处理这个案例:
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)
}
您仍然可以使用 "half-narrowed" 类型,但它只是一个类型别名,因此不存在路径依赖性问题。
我正在玩弄以下代码:
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[_]
(或类似的东西),这并不是编译器正在寻找的。我也知道将 case class Codec[_]
及其同伴移到特征之外可以解决问题(在使其采用 2 个类型参数之后)。如果需要隐式值,编译器应在隐式范围内包含所需类型的伴生对象。我的问题是:
- 如何将编译器指向依赖于路径的子类型,更具体地说:
- 是否可以更改
trait
的两个方法的签名(最好更改隐式参数的类型签名)以进行编译?如何从特征Codecs[_]
内部引用类型Acodecs.Codec[_]
? 比如,你如何在嵌套类型上做这种类型class的事情?
是否有处理此类问题的模式或东西?
问题是您的类型绑定到特定实例,因为它是内部 class。并且编译器不知道 implicitly[Codecs[A]]
给出的实例与它在下一行隐式找到的实例完全相同。例如,如果您显式传递它:
codecs.code[B](new A)(Codecs.ACodecs.Codec.ab)
您收到此错误消息:
type mismatch;
found : Codecs.ACodecs.Codec[B]
required: codecs.Codec[B]
因此它认为封闭的实例可能不同,因此类型不同。
我从未真正见过这种特定类型的隐式嵌套——即隐式类型class,其中包含路径相关的隐式类型classes。所以我怀疑是否存在处理它的模式,实际上我会建议不要这样做。这似乎过于复杂。以下是我个人如何处理这个案例:
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)
}
您仍然可以使用 "half-narrowed" 类型,但它只是一个类型别名,因此不存在路径依赖性问题。