Scala - Generi c неявный с нижней границей - PullRequest
2 голосов
/ 16 января 2020

Примите во внимание следующее:

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?

Ответы [ 2 ]

0 голосов
/ 19 января 2020

Решение оказалось, чтобы переместить параметр B с f на implicitOption, изменив их определения следующим образом.

implicit def implicitOption[B <: Super]: Option[B] = None
def f[A](a: A)(implicit i: Option[A]) = println("It worked")
0 голосов
/ 16 января 2020

В этом случае компилятору нужна помощь, чтобы выяснить, какой 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) не компилируется с "неявным не найдено".

Для более фундаментального понимания ко-и контравариантности, пожалуйста, обратитесь к документам . Проще говоря, ковариантный класс generi c «следует» за связями предков и потомков, в то время как контравариантные классы меняют направление. Для иллюстрации (в псевдо- scala):

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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...