Подтвердить что ты не робот

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

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

class List[+A]

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

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

Также дисперсия может быть эмулирована с помощью общих ограничений. Таким образом, мы также можем написать это

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

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

Итак, мои вопросы:

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

спасибо заранее:)

4b9b3361

Ответ 1

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

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

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

  • Чтобы написать аналог типа Java с помощью подстановочных знаков, например List<? extends Number>.
  • Чтобы написать аналог Java-типа, например List.

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

Ответ 2

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

Кстати, программирование в книге Scala Мартина Одерски, Лекса Лоуны и Билла Веннера имеет несколько замечаний относительно разницы. См. Главу 19 "Параметризация типов".