以下是我真正问题的简化版本:
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
这很有效,虽然我能以某种方式使它发挥作用,但我仍然不理解这种魔法背后的逻辑。
答案 0 :(得分:6)
您已经遇到了Scala类型推理系统的this limitation的另一种变体。
如果在第一种情况下,编译器将解析T
的{{1}},它正在寻找从普通旧f
到E.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}}。