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

Scala函数外部变量访问问题:结合备忘化示例代码解析

Great question! Let's break this down clearly—first explaining how Scala handles access to variables outside a function, then walking through that memoization code you highlighted.

Scala's Mechanism for Accessing Variables Outside a Function

In Scala, when an inner function (like the anonymous i => { ... } in your code) accesses variables or functions defined in an outer scope, this is enabled by closures. Here's the key details:

  • A closure captures a reference to the outer variable, not just its current value. This means if the outer variable is mutable (declared with var), the inner function can see and modify updates to that variable over time.
  • For immutable variables (declared with val), the closure captures the fixed value once, since it can't be changed later.
  • This allows inner functions to maintain state across multiple calls—exactly what's used in memoization to cache results.
Breaking Down the Memoization Code

First, let's fill in the implied else part of your code to make the logic complete:

def memoizedIsPrime: Int => Boolean = {
  def checkIfPrime(i: Int): Boolean = {
    2 to (i - 1) forall (x => i % x != 0)
  }
  var cache = Map.empty[Int, Boolean]
  i => {
    if (!cache.contains(i)) {
      print(s"Calling isPrime since input ${i} has not been seen before and caching the output")
      cache = cache updated(i, checkIfPrime(i))
    }
    cache(i)
  }
}

Now let's walk through how this works step by step:

  1. The checkIfPrime inner function: This holds the core logic to determine if a number is prime. It verifies that all integers from 2 up to i-1 do not divide i evenly. (Note: A more optimized version would check up to sqrt(i), but that's unrelated to the memoization pattern itself.)
  2. The mutable cache: var cache = Map.empty[Int, Boolean] initializes an empty map to store already computed prime check results. Using var lets us update this cache across multiple calls to memoizedIsPrime (we're technically reassigning the var to new immutable maps each time, but it behaves like a mutable cache for our purposes).
  3. The returned closure: The i => { ... } function is the actual memoized prime checker that gets assigned to memoizedIsPrime. Here's what happens when you call it with a number:
    • First, it checks if the input i is already present in the cache.
    • If not, it prints a status message, computes the prime check result via checkIfPrime(i), updates the cache with the new entry, then returns the computed result.
    • If i is already in the cache, it skips the expensive computation and directly returns the stored Boolean value from cache(i).

Key Notes About This Implementation

  • Side effects: This code has visible side effects (printing to the console, modifying the cache variable). In pure functional Scala, you might prefer using immutable state with a wrapper like scala.collection.mutable.Map or more functional patterns, but this is a simple, intuitive memoization example.
  • Thread safety: This implementation is not thread-safe. If multiple threads call memoizedIsPrime concurrently, there's a risk of race conditions when updating the cache. For thread-safe memoization, you'd need to use a concurrent collection (like java.util.concurrent.ConcurrentHashMap) or add synchronization around cache access.

内容的提问来源于stack exchange,提问作者pramesh

相关产品推荐
方舟 Agent Plan

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

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