Изменяемый вариант Scala?

Я хочу что-то вроде этого:

private val cachedResponse = mutable.Option.empty[A]

def get: A = cachedResponse getOrElseUpdate db.findModel()

def update: Unit = {
  db.updateModel
  cachedResponse.empty()    // set it to None/Option.empty
}

Я не ищу общую подобную этой, основанную на HashMap. Я попытался реализовать это с помощью var Option[A], но мне это показалось не очень идиоматическим:

private var cachedResponse: Option[A] = None

def get: A = cachedResponse getOrElse {
 cachedResponse = Option(db.findModel())
 cachedResponse.get
}

def update: Unit = {
  db.updateModel
  cachedResponse = None
}

person pathikrit    schedule 20.10.2014    source источник
comment
Быстрый поиск в Google нашел эту реализацию, которая выглядит как то, что вам нужно ...: blog.adamdklein.com/? p = 689   -  person experquisite    schedule 21.10.2014


Ответы (1)


В стандартную библиотеку нет встроенного.

Использование var, содержащего неизменяемый Option, является идиоматическим способом сделать это (при условии, что вы не можете переписать это, чтобы вообще не использовать состояние).

В противном случае вам следует создать свой собственный. Вот суть реализации:

class MutableOpt[A] {
  private[this] var myValue: A = _
  private[this] var loaded = false
  private def valueEquals(o: Any) = myValue == o
  def get = if (loaded) myValue else throw new NoSuchElementException("MutableOpt")
  def set(a: A): this.type = { loaded = true; myValue = a; this }
  def getOrSet(a: => A): A = {
    if (!loaded) {
      myValue = a
      loaded = true
    }
    myValue
  }
  def isEmpty = !loaded
  def nonEmpty = loaded
  def foreach[U](f: A => U): Unit = if (loaded) f(myValue)
  def transform(f: A => A): this.type = { if (loaded) myValue = f(myValue); this }
  def clear(): this.type = { loaded = false; this }
  def toOption = if (loaded) Some(myValue) else None
  override def toString = if (loaded) "MutableOpt("+myValue.toString+")" else "MutableOpt()"
  override def hashCode = if (loaded) myValue.hashCode else 1751
  override def equals(o: Any) = o match {
    case m: MutableOpt[_] =>
      (isEmpty && m.isEmpty) || (nonEmpty && m.nonEmpty && m.valueEquals(myValue))
    case _ => false
  }
}
object MutableOpt {
  def from[A](o: Option[A]) = {
    val m = new MutableOpt[A]
    o match {
      case Some(a) => m set a
      case _ =>
    }
    m
  }
}

Определите вместе с :paste, если используете REPL.

person Rex Kerr    schedule 21.10.2014
comment
LGTM. Спасибо, что поделился. Но в многопоточной среде в getrSet может быть какое-то состояние гонки. - person pathikrit; 21.10.2014
comment
Верно, что это как раз одно из преимуществ неизменяемости перед изменчивостью. - person Nader Ghanbari; 21.10.2014
comment
@wrick - Абсолютно точно так же, как почти все изменяемое. Вы можете сделать все операции атомарными, но при этом пострадает производительность. - person Rex Kerr; 21.10.2014