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 стойност за 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  
}

Ако искате да избегнете въвеждането на друго поле, можете да промените чертата, така че да не съдържа поле, а само методите getter и setter.

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
Да, работи. Трябваше и аз да се замисля. Но въвежда друга стойност, която държи слабата реф, която изглежда по-малко елегантна в духа на scala. - person abel; 21.10.2012
comment
Благодаря, Ким. Може би това е един от сценариите, при които scala кодът би бил многословен. - person abel; 24.10.2012

Не съм сигурен защо искате слаба препратка в клас case, но вероятно искате да можете да се докопате до стойността и иначе искате да е прозрачно, че всъщност е слаба - в противен случай можете просто да поставите WeakReference в класа case. Първо нека изградим удобна обвивка:

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, че показва оригиналния низ с ~ отпред (можете да промените това, разбира се), и най-важното, че можете да правите съпоставяне на шаблон на препратката (която ще съвпада само ако препратката е там). С това наоколо, сега можем да правим слаби препратки в класове case с минимален допълнителен шум:

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 съхранява вътрешно слаб реф, но дефинирането на параметъра като WeakReference в конструктора по подразбиране всъщност проваля тази цел. Вашето решение е много интересно и опростява много използването на WeakReference. - person abel; 21.10.2012