scala.Option的java.util.Map#computeIfAbsent类似物

时间:2018-11-18 08:29:21

标签: scala optional

我在Scala中有一个Option[…]类型的变量。

我需要:

  • 如果已经有一个值-返回该值;
  • 如果还没有值,请使用一些预定义的供应商方法中的值填充它,然后返回该值。

即它应该像一些长期计算的供应商方法的缓存一样。

我当然可以用愚蠢的方式做到这一点:

var cache: Option[X]
…
{
    if (cache.isEmpty) cache = Some(supplier())
    cache.get
}

但是我相信应该有一种Java Map#computeIfAbsent风格的简单代码。

在吗?

2 个答案:

答案 0 :(得分:2)

您不能在一行中完成此操作,因为您必须先进行赋值以更新cache,然后进行提取以获取值:

cache = cache orElse Some(supplier())
cache.get

赋值返回Unit,因此您不能使用赋值的结果来读取值。


这种代码模式有时称为“记忆”,并且在stackoverflow和其他地方有很多通用代码示例。

答案 1 :(得分:-1)

经过一番思考,我意识到甚至在理论上Option的Scala中都不存在这样的事情。因为Option被设计为不可变的(与Java Map不同),所以它没有更新其值的更新方法(甚至更多— NoneSome不同Option的子类)。我们都无法编写诸如def getOrFill[T](ref cache: Optional[T])(supplier: => T): T之类的外部辅助方法,因为Scala不支持ref(输入-输出)参数。

我们可能最好的办法是创建一个单独的用于缓存的类(用Option包装):

  • 变种1:

    class Cache[T] {
      def getOrFill(supplier: => T): T = {
        if (value.isEmpty) value = Some(supplier)
        value.get
      }
      private var value: Option[T] = None
    }
    

    然后

    var cache = new Cache[X]
    …
    cache.getOrFill(supplier())
    
  • 变体2-如果在缓存的整个生命周期中都使用了相同的供应商(最可能的情况):

    class Cache[T](supplier: => T) {
      def getOrFill: T = {
        if (value.isEmpty) value = Some(supplier)
        value.get
      }
      private var value: Option[T] = None
    }
    

    然后

    var cache = new Cache[X](supplier())
    …
    cache.getOrFill
    

注意:我没有考虑以上代码的差异(也许应该更改差异)。