Scala-具有下界的通用隐式

问题描述 投票:2回答:2

请考虑以下内容:

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的隐式参数?

scala generics implicit-conversion implicit
2个回答
0
投票

在这种情况下,编译器需要一些帮助来确定要使用哪个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]

0
投票

解决方案原来是通过像这样更改其定义将参数Bf移至implicitOption

implicit def implicitOption[B <: Super]: Option[B] = None
def f[A](a: A)(implicit i: Option[A]) = println("It worked")
© www.soinside.com 2019 - 2024. All rights reserved.