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。