При использовании ковариационных обозначений или общих границ в Scala

StackOverflow https://stackoverflow.com/questions/3663609

Вопрос

В Scala Variance можно определить с дисперсионными операторами, такими как + и - на общий аргумент типа. Например List Тип является ковариантным в стандартной библиотеке.

class List[+A]

Таким образом, функция с ковариантным списком может быть определена так:

def foo[A](list : List[A])

Также дисперсию можно эмулировать общие границы. Итак, мы также можем написать это

def foo[A](list : List[_:< A])

Конечно, это не имеет смысла, потому что list уже ковариант. Но тот же трюк можно сделать для типов, которые не являются ковариантными. (подобно Stack). Конечно, также могут быть созданы новые типы из стека (наследство агрегации), которое является ковариантным.

Так что мои вопросы:

  1. Когда следует использовать общие оценки для дисперсии? И когда мы должны создать новый ковариантный тип?
  2. Являются общими границами только для дисперсии, или они могут объявить больше (языковые концепции).
  3. Если они полезны только для дисперсии, являются обязательными только для совместимости с Java?

THX заранее :)

Это было полезно?

Решение

Если тип естественным образом ковариант или контравариант, вы должны объявить его так. Ваши пользователи будут благодарить вас за это. Дисперсия на сайте использует действительно в основном там из-за Java. Точнее, такой тип, как Array[T <: Number] рассматривается как сокращение для экзистенциального типа:

ArrayBuffer[T] forSome { type T <: Number }

Существующие типы имеют красивый громоздкий синтаксис в Scala. Это своего рода преднамеренного, потому что мы не рекомендуем вам много использовать. Когда бы вам понадобится экзистенциальный тип?

  1. Написать аналог типа Java с подстановочными картами, такими как List<? extends Number>.
  2. Написать аналог Java сырого типа, например List.

В Java, сырьевые типы и типы подстановочных знаков не совсем одинаковы, и ни одна не совсем совпадает с экзистенциальным типом (хотя мы знаем, что они не являются, это довольно сложно указывать именно то, что они). Но они достаточно близко к экзистенциалам на практике, так что Скала уходит с картирования их к такому типу.

Другие советы

  1. При создании нового родового типа, скажем, foo [t], вы должны стараться изо всех сил, чтобы определить, является ли этот тип ковариантным, контраварианным или инвариантным и объявить его FOO [+ T], FOO [-T] или FOO [T] соответственно. По общему признанию, это может быть немного сложно. Тем не менее, он освобождает пользователя Foo принять это решение каждый раз, когда ей нужно использовать Foo, используя общие границы. Короче говоря: предпочитают декларационную дисперсию сайта по поводу отклонения сайта вызова, когда дисперсия является свойством самого типа.

Кстати, программирование в Scala Book Book Martin Odersky, Lex Spoon и Bill Venners имеет отличные нарастания о дисперсии. См. Главу 19 Тип параметризации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top