Ответ 1
У набора типа Set[A]
должен быть метод, который проверяет, есть ли элемент типа A
в наборе. Этот метод (apply
) должен иметь параметр типа A
, представляющий этот элемент, и этот параметр находится в контравариантной позиции. Это означает, что множества не могут быть ковариантными в своем параметре типа A
. Таким образом, это не расширение функционального интерфейса, что делает невозможным наличие ковариантных неизменяемых множеств, это наличие контравариантного метода apply
.
И по соображениям удобства имеет смысл расширить интерфейс Function1
, чтобы иметь возможность передавать наборы и рассматривать их как функции.
В отличие от абстракции последовательности нет метода, который проверяет, находится ли элемент в последовательности, он имеет только метод индексирования - apply
принимает целочисленный индекс и возвращает элемент в этом индексе. Последовательности также определяются как функции, но функции типа Int => A
(которые ковариантны в A
), а не A => Boolean
, как наборы.
Если вы хотите узнать больше о том, как безопасность типов будет нарушена, если наборы были определены как ковариантные в своем параметре типа A
, см. этот пример, в котором реализация набора делает некоторую запись частным членам по причинам кэширования поисковых запросов (ниже @uV
- аннотация, которая отключает проверку дисперсии и expensiveLookup
предназначена для имитации вызова дорогостоящей проверки, если элемент находится в наборе):
import annotation.unchecked.{uncheckedVariance => uV}
trait Set[+A] {
def apply(elem: A @uV): Boolean
}
class CachingSet[+A >: Null] extends Set[A] {
private var lastLookup: (A @uV, Boolean) = (null, false)
private def expensiveLookup(elem: A @uV) = (elem, true)
def apply(elem: A @uV): Boolean = {
if (elem != lastLookup._1) lastLookup = expensiveLookup(elem)
lastLookup._2
}
def lastQueriedElement: A = lastLookup._1
}
object Main extends App {
val css = new CachingSet[String]
val csa: CachingSet[AnyRef] = css
csa.apply(new AnyRef)
val s: String = css.lastQueriedElement // you'll get a ClassCastException here
}