1. 概述

在本教程中,我们将深入探讨 Scala 中方法(def)、变量(var)、值(val)以及惰性值(lazy val)之间的异同。

如果你对 Scala 的核心特性感兴趣,可以参考我们的 Scala 入门指南lazy val 使用详解

2. 方法(def)

方法是惰性求值的,也就是说,只有在调用时才会执行其代码体。我们可以通过一个简单的例子来验证这一点:

object Methods extends App {
  def method: Int = {
    println("method")
    1
  }

  println("After method declaration")
  println(method)
  println(method)
}

控制台输出如下:

After method declaration
method
1
method
1

可以看到,每次调用 method 都会重新执行方法体内的逻辑。

另外,方法是不可变的 ❌,一旦定义就不能被重新赋值。尝试修改方法绑定的值会导致编译错误:

def secretNumber: Int = 5
secretNumber = 1 // 编译报错:reassignment to method

⚠️ 提示:虽然语法上看起来像赋值操作,但 def 定义的是行为而非状态。

3. 变量(var)

变量是及早求值的,它在声明时就会立即执行初始化块。来看下面这个例子:

object Variables extends App {
  var variable: Int = {
    println("variable")
    1
  }

  println("After variable declaration")
  println(variable)
  println(variable)
}

输出结果为:

variable
After variable declaration
1
1

可以看出,初始化块只执行了一次,在变量声明的时候。

✅ 与方法不同,变量是可以被重新赋值的:

var secretNumber: Int = 5
secretNumber = 1 // ✅ 合法操作

⚠️ 踩坑提醒:可变变量虽好用,但容易引发并发问题或副作用,请谨慎使用。

4. 值(val)

值也是及早求值的,和变量一样,在声明时就完成初始化:

object Values extends App {
  val value: Int = {
    println("value")
    1
  }

  println("After value declaration")
  println(value)
  println(value)
}

输出结果为:

value
After value declaration
1
1

❌ 与变量不同,值是不可变的。尝试修改值会导致编译失败:

val secretNumber: Int = 5
secretNumber = 2 // ❌ 编译错误:reassignment to val

✅ 简单粗暴总结:val 是只读的,适合用于表达不变的状态。

5. 惰性值(lazy val)

惰性值结合了方法的延迟性和值的单次求值特性。它在首次访问时才会执行初始化,并且只执行一次:

object LazyValues extends App {
  lazy val lazyValue: Int = {
    println("lazy value")
    1
  }

  println("After lazy value declaration")
  println(lazyValue)
  println(lazyValue)
}

输出如下:

After lazy value declaration
lazy value
1
1

可以看到,初始化块仅在第一次访问 lazyValue 时执行。

❌ 同样地,惰性值也是不可变的:

lazy val secretNumber: Int = 5
secretNumber = 1 // ❌ 编译错误:reassignment to val

⚠️ 注意:lazy val 的实现依赖于同步机制,在高并发场景下可能成为性能瓶颈。

6. 小结

通过本文的学习,我们了解了 Scala 中四种基本声明方式的核心区别:

类型 求值策略 是否可变
def 惰性 ❌ 不可变
var 及早 ✅ 可变
val 及早 ❌ 不可变
lazy val 延迟(仅一次) ❌ 不可变

如需查看完整示例代码,欢迎前往 GitHub 仓库:Baeldung/scala-tutorials


原始标题:Def, Var & Val in Scala