Scala с использованием WeakReference в классе Case

Я хочу написать класс case в scala, который содержит scala.ref.WeakReference для какого-либо другого объекта. Интересно, что лучше всего сделать в scala?

У меня было несколько мыслей по этому поводу, и первая была такая:

case class CC1(ref: Any) {
    private val weakRef: WeakReference[Any] = WeakReference(ref)

    def get: Any = weakRef()
}

Но это просто не работает, потому что scala автоматически сгенерирует в CC1 значение val для ref, которое содержит сильную ссылку.

Моя вторая мысль была:

case class CC2(private val weakRef: WeakReference[Any]) {
    def get: Any = weakRef() 
}

Это сработало. Однако это не очень удобно с точки зрения повторного использования кода - что, если weakRef и get происходят из базового класса / трейта, например:

trait T3 {
    protected var weakRef: WeakReference[Any] = null

    def get: Any = if(weakRef != null) weakRef() else null
}

case class CC3(/* how should I initialize weakRef in T3 */) extends T3 {
}

Как бы вы написали код? Что бы вы посоветовали, пожалуйста? Заранее спасибо!


person abel    schedule 20.10.2012    source источник


Ответы (2)


Что в этом плохого?

case class CC3(private val wr:WeakReference[AnyRef]) extends T3 {
  weakRef = wr  
}

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

trait T3 {
  protected def weakRef: WeakReference[AnyRef]
  protected def weakRef_=(wr:WeakReference[AnyRef])

  def get: Any = if(weakRef != null) weakRef() else null
}

Затем вы реализуете эти методы в своем классе case.

case class CC3(private var wr:WeakReference[AnyRef]) extends T3 {
  override protected def weakRef = wr
  override protected def weakRef_=(w:WeakReference[AnyRef]) { wr = w }
}
person Kim Stebel    schedule 20.10.2012
comment
Да, это работает. Я тоже должен был подумать об этом. Но он вводит еще один val, содержащий слабую ссылку, которая выглядит менее элегантно в духе scala. - person abel; 21.10.2012
comment
Спасибо, Ким. Возможно, это один из сценариев, в которых код scala будет многословным. - person abel; 24.10.2012

Я не уверен, почему вам нужна слабая ссылка в классе case, но, по-видимому, вы хотите иметь возможность получить значение, а в противном случае хотите, чтобы оно было прозрачным, что оно на самом деле слабое - в противном случае вы можете просто поставить WeakReference в случае класса. Сначала создадим удобную оболочку:

class Weakly[A](wr: java.lang.ref.WeakReference[A]) {
  def apply() = wr.get
  def get = Option(wr.get)
  def weak = wr
  override def hashCode = { val a = wr.get; if (a==null) wr.hashCode else a.hashCode }
  override def equals(a: Any) = a==wr.get
  override def toString = "~"+wr.get
}
object Weakly {
  def apply[A](a: A) = new Weakly(new java.lang.ref.WeakReference(a))
  def unapply[A](wa: Weakly[A]) = Option(wa())
}
implicit def strengthen_on_demand[A](w: Weakly[A]) = w()
implicit def weaken_on_demand[A](a: A) = Weakly(a)

Теперь наша обернутая слабая ссылка обернута дважды, с тем преимуществом, что она отображает исходные hashCode и equals, отображает исходную строку с ~ впереди (вы, конечно, можете это изменить), и, что наиболее важно, вы можете выполнять сопоставление с образцом на ссылка (которая будет соответствовать только в том случае, если ссылка есть). Теперь мы можем делать слабые ссылки в классах с минимумом лишней суеты:

scala> case class CC1(s: Weakly[String]) {}
defined class CC1

scala> val cc = CC1("fish")
cc: CC1 = CC1(~fish)

scala> cc match { case CC1( Weakly(s) ) => s; case _ => "(nope)" }
res0: String = fish

scala> val s: String = cc.s
s: String = fish

scala> cc.s.weak.clear

scala> cc match { case CC1( Weakly(s) ) => s; case _ => "(nope)" }
res2: String = (nope)
person Rex Kerr    schedule 20.10.2012
comment
Ты прав. Я хотел сделать прозрачным тот факт, что класс case хранит внутри weakref, но определение параметра как WeakReference в конструкторе по умолчанию фактически не позволяет достичь этой цели. Ваше решение очень интересное, и оно значительно упрощает использование WeakReference. - person abel; 21.10.2012