You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala函数结果缓存方法及混淆矩阵度量类方法调用疑问

1. 如何在Scala中缓存函数结果?

在Scala里实现函数结果缓存(也就是记忆化)有不少实用方案,我给你整理几个常用的:

  • 手动实现基础缓存:用Map存储已计算的输入和对应结果,适合简单场景。比如给一个耗时的纯函数加缓存:

    def calculateHeavy(n: Int): Int = {
      println(s"正在计算n=$n") // 用于验证是否重复计算
      Thread.sleep(1000)
      n * 3
    }
    
    // 封装带缓存的版本
    val memoizedCalculate = {
      val cache = scala.collection.mutable.Map.empty[Int, Int]
      (n: Int) => cache.getOrElseUpdate(n, calculateHeavy(n))
    }
    

    第一次调用memoizedCalculate(5)会执行计算,后续调用直接取缓存值。

  • 用lazy val缓存特定输入结果:如果只需要缓存固定几个输入的结果,lazy val是个轻量选择,它只会在第一次访问时计算,之后直接返回缓存值:

    lazy val cachedResultFor10 = calculateHeavy(10)
    
  • 借助第三方缓存库实现复杂策略:如果需要过期时间、容量限制这类高级特性,推荐用Caffeine或Guava这类成熟库。以Caffeine为例:

    import com.github.benmanes.caffeine.cache.Caffeine
    
    val cache = Caffeine.newBuilder()
      .maximumSize(150) // 最大缓存150个条目
      .expireAfterWrite(10, java.util.concurrent.TimeUnit.MINUTES) // 写入后10分钟过期
      .build[Int, Int]()
    
    def memoizedHeavy(n: Int): Int = cache.get(n, calculateHeavy)
    

    get方法会先查缓存,不存在则调用目标函数计算并缓存结果。

  • 封装通用记忆化工具函数:可以写一个通用方法,快速给任意纯函数加上缓存能力:

    def memoize[A, B](f: A => B): A => B = {
      val cache = scala.collection.mutable.Map.empty[A, B]
      a => cache.getOrElseUpdate(a, f(a))
    }
    
    val memoizedHeavyFunc = memoize(calculateHeavy)
    

2. Measure类中fMeasure方法的调用次数问题

首先提个小问题:你写的require(tp < 0); require(fp < 0); require(fn < 0)条件是反的,应该是tp >= 0; fp >= 0; fn >= 0,不然创建Measure实例时会直接抛出非法参数异常。

回到你的核心疑问:调用fMeasure时,precision和recall会各自被调用两次吗?

答案是:默认情况下会各自被调用两次。因为Scala默认是严格求值,在fMeasure的表达式2 * (precision * recall) / (precision + recall)里,precision和recall各被引用了两次,每一次引用都会触发一次方法调用。

你可以加打印语句验证:

case class Measure(tp: Int, fp: Int, fn: Int){ 
  require(tp >= 0); require(fp >= 0); require(fn >= 0) 
  def precision: Double = {
    println("调用precision方法")
    tp.toDouble / (tp + fp) // 注意转成Double,避免整数除法丢失精度
  }
  def recall: Double = {
    println("调用recall方法")
    tp.toDouble / (tp + fn)
  }
  def fMeasure: Double = 2 * (precision * recall) / (precision + recall) 
}

val m = Measure(10, 5, 3)
m.fMeasure

运行后会输出:

调用precision方法
调用recall方法
调用precision方法
调用recall方法

这就证明了两个方法各被调用了两次。

如果想优化成仅调用一次,只需要在fMeasure里先把结果存为局部变量,之后复用即可:

def fMeasure: Double = {
  val p = precision
  val r = recall
  2 * (p * r) / (p + r)
}

修改后再调用fMeasure,就只会打印一次调用precision方法和调用recall方法了。

补充说明:Scala不会自动对这类方法调用做缓存优化,必须显式将结果赋值给变量来复用。


内容的提问来源于stack exchange,提问作者THIS USER NEEDS HELP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:35:43