Scala:隐式参数中的错误

时间:2013-06-24 19:39:06

标签: scala implicit-conversion

以下是我真正问题的简化版本:

class Z[T]
object E extends Enumeration {
  implicit val z = new Z[Value] 
  val X, Y = Value
}
implicit def f[T : Z] = (getter: T) => 0
implicit def o[T](v: Option[T])(implicit toInt: T => Int) = 0
def e: Option[E.Value] = null
val b: Int = e

这是有效的,b隐式转换为o(e)(f(E.z))。但随着以下小变化:

implicit def f[T : Z] = (setter: T => Unit) => 0
implicit def o[T](v: Option[T])(implicit toInt: (T => Unit) => Int) = 0

它找不到合适的隐含值E.z虽然与原始代码没有本质区别,但是手动显式转换为o(e)(f(E.z))仍然有效。

我知道隐式参数的实现尚未完成,仍有许多未解决的问题。如果这是其中之一,我想向Scala贡献者报告。所以我的问题是,a)这真的是一个错误吗? b)如果是这样,我在哪里以及如何提交错误以便将来修复它?

更新

特拉维斯的回答就像一个魅力!顺便说一句,上面的代码解决了我原来的问题:

implicit object E extends Enumeration { val X, Y = Value }
implicit object F extends Enumeration { val X, Y = Value }
implicit def f[T <: Enumeration](getter: T#Value)(implicit e: T) = 0
implicit def o[T](v: Option[T])(implicit toInt: T => Int) = 0
val b: Int = Some[E.Value](null)

在这段代码中,情况恰恰相反:它适用于setter版本,但不适用于更简单的getter版本。编译器抱怨说使用E或F作为隐式参数是令人困惑的,尽管使用F实际上并不编译也没有意义。我设法通过做类似的事情来实现它:

implicit def f[S <% T => T, T <: Enumeration](getter: T#Value)(implicit e: T) = 0

这很有效,虽然我能以某种方式使它发挥作用,但我仍然不理解这种魔法背后的逻辑。

1 个答案:

答案 0 :(得分:6)

您已经遇到了Scala类型推理系统的this limitation的另一种变体。

如果在第一种情况下,编译器将解析T的{​​{1}},它正在寻找从普通旧fE.Value的隐式转换,但不是第二个,它想要从Int(即E.Value => Unit)转换为Function1[E.Value, Unit]

幸运的是,在这种情况下有一个简单的解决方法 - 只需使用视图绑定:

Int

这将是以下类似的东西:

implicit def f[F <% T => Unit, T: Z] = (setter: F) => 0

现在,当编译器希望从implicit def f[F, T](implicit st: F <:< (T => Unit), ev: Z[T]) = (setter: F) => 0 转换为E.Value => Unit时,它将能够立即将Int解析为F,然后E.Value => Unit转换为T {1}}。