请考虑以下内容:
class Super
class Sub extends Super
implicit val implicitOption: Option[Super] = None
def f[A, B >: A](a: A)(implicit i: Option[B]) = println("It worked")
如果我调用f(new Super)
,它可以正常工作,但是f(new Sub)
给我一个编译错误(找不到参数i
的隐式值。]
为什么implicitOption
不能用作A = Sub
的隐式参数?
在这种情况下,编译器需要一些帮助来确定要使用哪个B
。所以
f[Sub, Super](new Sub)
效果很好。
因为Option
是协变的-这意味着您可以在需要Option[Sub]
的地方传递Option[Super]
,反之则不能。
为了使这项工作有效,您需要一个逆变类(现在将其称为ContraOption
-这样就可以在需要ContraOption[Super]
的地方传递ContraOption[Sub]
。
继续您的示例:
class Super
class Sub extends Super
implicit val implicitOption: Option[Super] = None
sealed abstract class ContraOption[-A]
case object ContraNone extends ContraOption[Any]
case class ContraSome[A](value: A) extends ContraOption[A]
implicit val implicitContraOption: ContraOption[Super] = ContraNone
def f[A, B >: A](a: A)(implicit i: Option[B]) = println("It worked")
def f2[A, B >: A](a: A)(implicit i: ContraOption[B]) = println("It worked 2")
f(new Super) // It worked
f2(new Sub) // It worked 2
请注意,尝试执行f(new Sub)
(如您的示例)和f2(new Super)
都失败,并显示“未发现隐式”。
有关协方差和逆方差的更基本的了解,请参阅docs。但简单地说,协变泛型类“跟随”祖先-后继链接,而反变类则逆转方向。为了说明(以伪标量):
class Super
class Sub extends Super
class Covariant[+A]
class Contravariant[-A]
This gives us the following relationships:
Sub <: Super
Covariant[Sub] <: Covariant[Super]
Contravariant[Super] <: Covariant[Sub]
解决方案原来是通过像这样更改其定义将参数B
从f
移至implicitOption
。
implicit def implicitOption[B <: Super]: Option[B] = None
def f[A](a: A)(implicit i: Option[A]) = println("It worked")