Вопрос по – Модификаторы Scala и параметризация типов

12

Я создаю класс для запоминания.

Каждый класс запоминает тип функции и имеет следующее определение:

<code> class MemoizedFunction1[-T1, +R](f: T1 => R) {
    private[this] val cache = mutable.Map[T1, R]()
    def apply(t: T1): R = cache.getOrElseUpdate(t,f(t))
  }
</code>

Это хорошо компилируется и работает как положено. Однако, если я удалю измененныйprivate[this] Я получаю следующую ошибку:

<code>contravariant type T1 occurs in invariant position in type => scala.collection.mutable.Map[T1,R] of value cache
</code>

Почему при удалении модификатора контравариантный тип T1 внезапно мешает инвариантному типу карты? Как модификаторы влияют на параметризацию типа?

Tangential:cache.getOrElseUpdate(t,f(t)) - Я верю, что это вызоветf(t) каждый раз, в кеше или нет. Нужно больше лени. Dan Burton
На самом деле это параметр вызова по имени (согласно Scala-lang.org / апи / ток / Скала / Коллекция / изменяемые / Map.html) что означает, что оно не будет оценено, еслиgetOrElseUpdate хотеть. Дальнейшее тестирование подтвердило это. JaimeJorge
А, ты прав. Мне нужно больше познакомиться со Scala. Dan Burton
Я новичок, это может не иметь смысла ... но является ли ключевой параметр в получателе для кеша неоднозначным вне контекста этого экземпляра? Если, например, я ссылаюсь на MemoizedFunction [String, String] как MemoizedFunction [Object, String], похоже, что тип кэша отключен. Ed Staub

Ваш Ответ

3   ответа
6

но это рассматривается в разделе 4.5 (Аннотации отклонений) Scala Language Specification 2.9 на странице 45

Ссылки на параметры типа в объектно-частных или объектно-защищенных значениях, переменных или методах (§5.2) класса не проверяются на их позицию отклонения. В этих элементах параметр типа может появляться где угодно, не ограничивая его допустимые аннотации отклонений.

Чтобы упростить ваш пример, согласно спецификации, это нормально:

class Inv[T]

class Foo[-T] {
  private[this]   val a: Inv[T] = sys.error("compiles")
  protected[this] val b: Inv[T] = sys.error("compiles")
}

Но если вы удалите[this] это будет жаловаться. На некотором уровне это имеет смысл, поскольку, если он не является частным объектом или защищен, контравариантный тип возврата может просочиться за пределы объекта и вызвать ошибку времени выполнения.

Так что это вопрос инкапсуляции. Дисперсия содержится, следовательно, не проблема. Потрясающе. Благодарност JaimeJorge
6

[this].

Без[this] вы можете добавить методgetOtherCache:

class MemoizedFunction1[-T1, +R](f: T1 => R) { 
  private val cache = mutable.Map[T1, R]() // trait Map[A, B] extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
  def apply(t: T1): R = cache.getOrElseUpdate(t,f(t))

  def getOtherCache(other: MemoizedFunction1[T1, R]) {
    val otherCache: mutable.Map[T1, R] = other.cache;
  }
}

class A
class B extends A

val mf1: MemoizedFunction1[B, B] = new MemoizedFunction1[B, B](b => b)

val mf2: MemoizedFunction1[B, B] = new MemoizedFunction1[A, B](a => new B)
// mf2 is MemoizedFunction1[B, B]
// mf2 contains mutable.Map[A, B]

mf1.getOtherCache(mf2) //Error! mf2.cache is NOT mutable.Map[B, B]!
Хороший пример. Я проверил источник Lampsvn.epfl.ch / ПРОФ / Scala / браузер / Scala / теги / R_2_9_1_final / SRC / ...) и без разницы. Так что имеет смысл, что ваш пример дает ошибку. Спасибо вам за эту информацию JaimeJorge
@ JaimeJorge: Это может звучать глупо, но знаете ли вы, что есть онлайн-документация? Это удобнее, чем исходный код: Scala-lang.org / апи / ток / ... senia
@ JaimeJorge: Без кода или документации: ключевой параметр типа Map просто не может быть противоположностью.Map[A, B] не может бытьMap[B, B] из-заkeys метод, который возвращаетIterable[TKey]. senia
:) Я знаю. Я просто посмотрел на код, чтобы быть уверенным в отклонениях (в случае, если документация API не содержит аннотаций отклонений). Глядя на (например) Scala-lang.org / апи / ток / Скала / Коллекция / неизменны / list.html Теперь я знаю, что это явно в API JaimeJorge
2

Программирование в Scala затрагивает эту тему в разделе 19.7 Личные данные объекта: «Доступ к закрытым членам объекта возможен только из объекта, в котором они определены. Оказывается, доступ к переменным из того же объекта, в котором они определены, не вызывает проблем с дисперсией.»

На самом деле это так. Благодарность JaimeJorge

Похожие вопросы