Дисперсионная функция карты списка Scala

У меня есть вопрос, который меня беспокоит. Списки в Scala являются ковариантными (List[+A])

Допустим, у нас есть эти классы:

class A  
class B extends A

map функция List[B] берет на себя функцию f: B => C

Но я также могу использовать f: A => Cкоторый является подклассом f: B => C
и это полностью имеет смысл.

То, что я в настоящее время смущен тем, что map Функция должна принимать только те функции, которые являются суперклассами исходной функции (поскольку функции противоречивы по своим аргументам), что не применимо в приведенном мной примере.

Я знаю, что что-то не так с моей логикой, и я бы хотел просветить.

2 ответа

Ваша ошибка заключается в предположении, что map(f: A => C) должны принимать только те функции, которые являются суперклассами A => C,

Хотя на самом деле, map будет принимать любую функцию, которая является подклассом A => C,

В Scala параметр функции всегда может быть подклассом требуемого типа.

Ковариация A в List[A] только говорит вам, что везде, где List[A] требуется, вы можете предоставить List[B], пока B <: A,

Или, проще говоря: List[B] может рассматриваться как подкласс List[A],

Я собрал небольшой пример, чтобы объяснить эти два поведения:

class A  
class B extends A

// this means: B <: A

val listA: List[A] = List()
val listB: List[B] = List()

// Example 1: List[B] <: List[A]
// Note: Here the List[+T] is our parameter! (Covariance!)

def printListA(list: List[A]): Unit = println(list)

printListA(listA)
printListA(listB)

// Example 2: Function[A, _] <: Function[B, _]
// Note: Here a Function1[-T, +R] is our parameter (Contravariance!)

class C

def fooA(a: A): C = ???
def fooB(b: B): C = ???

listB.map(fooB)
listB.map(fooA)

Попробуйте!

Надеюсь, это поможет.

Как вы уже подозревали, вы тут все путаете.

С одной стороны, у вас есть List[+A], что говорит нам кое-что об отношениях между List[A] а также List[B], учитывая отношения между A а также B, Дело в том, что List ковариантен в A просто означает, что List[B] <: List[A] когда B <: A, как вы уже знаете, знаете.

С другой стороны, List выставляет метод map изменить его "содержимое". Этот метод на самом деле не заботится о List[A], но только о Aс, так что дисперсия List здесь не имеет значения Здесь вас смущает то, что есть некоторая подтипировка, которую следует учитывать: map принимает аргумент (A => C в данном случае, но это не очень актуально), и, как обычно, с методами и функциями, вы всегда можете заменить его аргумент чем-либо, что является его подтипом. В вашем конкретном случае, любой AcceptedType будет хорошо, пока AcceptedType <: Function1[A,C], Дисперсия, которая имеет значение здесь Functionх, не List"S.

Другие вопросы по тегам