【发布时间】:2016-12-06 05:00:46
【问题描述】:
我有以下代码:
case class Custom(value: Int)
case class Custom2(value: Float)
case class MappedEncoding[I, O](f: I => O)
trait Decoders {
type BaseDecoder[T] = () => T
type Decoder[T] <: BaseDecoder[T]
}
trait ConcreteDecoders extends Decoders {
type Decoder[T] = ConcreteDecoder[T]
case class ConcreteDecoder[T](decoder: () => T) extends BaseDecoder[T] {
def apply(): T = decoder()
}
implicit def optionDecoder[T](implicit d: Decoder[T]): Decoder[Option[T]] =
ConcreteDecoder[Option[T]](() => Some(d()))
implicit def mappedDecoder[I, O](implicit mapped: MappedEncoding[I, O], decoder: Decoder[I]): Decoder[O] =
ConcreteDecoder[O](() => mapped.f(decoder()))
implicit def intDecoder: Decoder[Int] = ConcreteDecoder[Int](() => 1)
implicit def floatDecoder: Decoder[Float] = ConcreteDecoder(() => 1)
}
class ConcreteContext extends ConcreteDecoders {
}
case class TestObject() {
implicit val customDecoder = MappedEncoding[Int, Custom](Custom)
implicit val custom2Encoder = MappedEncoding[Custom2, Float](_.value) // 1
implicit val custom2Decoder = MappedEncoding[Float, Custom2](Custom2)
def a(c: ConcreteContext): Unit = {
import c._
implicitly[Decoder[Option[Custom]]] // 2
// implicitly[Decoder[Float]] // 3
implicitly[Decoder[Option[Float]]]
()
}
}
object Main extends App {
implicit val c = new ConcreteContext()
TestObject().a(c)
// TestObject(a).()
}
它在 Scala 2.11.8 和 2.12.0 中无法编译并出现错误:
diverging implicit expansion for type c.Decoder[Option[Float]]
[error] starting with method intDecoder in trait ConcreteDecoders
[error] implicitly[Decoder[Option[Float]]]
使用-Xlog-implicits 选项会产生较长的输出,但最有趣的部分是:
floatDecoder is not a valid implicit value for c.Decoder[Float] because:
[info] diverging implicit expansion for type c.Decoder[T]
[info] starting with method intDecoder in trait ConcreteDecoders
[info] implicitly[Decoder[Option[Float]]]
将c: CustomContext 从方法参数移动到案例类构造函数参数使其编译。我认为可能是它改变了隐含的搜索范围。
以下操作之一也使其编译:
- 用
1标记的注释行(== 第 1 行) - 评论第 2 行
- 取消注释第 3 行
看起来解析 implicitly[Decoder[Option[Custom]]] 会使 Scala 编译器处于影响解析 implicitly[Decoder[Option[Float]]] 的状态。
为什么会发生这种情况,如何在不从方法参数中移动 c: ConcreteContext 的情况下使其编译?
P.S. 这是重现问题的简化代码。真正的代码要复杂得多,我需要支持ConcreteContext作为方法参数传递的情况。
【问题讨论】:
-
这里肯定有问题。这似乎与SI-9625 有点相关。当您将方法参数转换为构造函数参数时,该问题也会消失。在旁注中,让您的
Decoder成为Function0的子类型也可能不是最好的主意。 -
@Jasper-M 由于stackoverflow.com/q/40391732/746347,我将
Decoder设为Function0的子类型。 -
def a(c: ConcreteContext): Unit内的明显解决方法def a(c: ConcreteContext): Unit是否足以满足您的需求? -
谢谢!这很有趣,即使
val c0 = c; import c0._也足够了。但我应该指出我不能改变def a()的实现。这是我图书馆的用户编写的代码。所以我们应该想想我们可以用ConcreteContext、Decoders实现做些什么。当然,首先我想找到这些奇怪事物的解释。