Scala中的 var 和 val 定义有什么区别?为什么语言需要两者?你为什么选择 val 而不是 var ,反之亦然?
12 回答
55
虽然很多人已经回答了 Val 和 var 之间的区别 . 但有一点要注意的是 val is not exactly like final 关键字 .
我们可以使用递归来改变val的值,但是我们永远不能改变final的值 . 最终比Val更稳定 .
def factorial(num: Int): Int = {
if(num == 0) 1
else factorial(num - 1) * num
}
方法参数默认为val,并且每个调用值都在更改 .
19
Val 表示其 final ,不能 reassigned
然而, Var 可以是 reassigned later .
6
正如许多其他人所说,分配给 val 的对象无法替换,并且分配给 var 的对象可以 . 但是,所述对象可以修改其内部状态 . 例如:
class A(n: Int) {
var value = n
}
class B(n: Int) {
val value = new A(n)
}
object Test {
def main(args: Array[String]) {
val x = new B(5)
x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one.
x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one.
x.value.value = 6 // Works, because A.value can receive a new object.
}
}
因此,即使我们无法更改分配给 x 的对象,我们也可以更改该对象的状态 . 然而,它的根源是 var .
def toNum(q: scala.collection.immutable.Queue[Int]) = {
def recurse(qr: scala.collection.immutable.Queue[Int], num: Int): Int = {
if (qr.isEmpty)
num
else {
val (digit, newQ) = qr.dequeue
recurse(newQ, num * 10 + digit)
}
}
recurse(q, 0)
}
因为我不能重用一些变量来跟踪我的 num ,就像在前面的例子中一样,我需要求助于递归 . 在这种情况下,它是一个尾递归,具有相当不错的性能 . 但情况并非总是如此:有时候没有好的(可读的,简单的)尾递归解决方案 .
但请注意,我可以重写该代码以同时使用 immutable.Queue 和 var !例如:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
var qr = q
var num = 0
while (!qr.isEmpty) {
val (digit, newQ) = qr.dequeue
num *= 10
num += digit
qr = newQ
}
num
}
不同之处在于 var 可以重新分配,而 val 则不能 . 任何实际分配的可变性或其他方面都是一个副问题:
import collection.immutable
import collection.mutable
var m = immutable.Set("London", "Paris")
m = immutable.Set("New York") //Reassignment - I have change the "value" at m.
鉴于:
val n = immutable.Set("London", "Paris")
n = immutable.Set("New York") //Will not compile as n is a val.
因此:
val n = mutable.Set("London", "Paris")
n = mutable.Set("New York") //Will not compile, even though the type of n is mutable.
在计算中恰好非常重要的区别(因为这两个概念定义了编程的本质),并且OO几乎完全模糊了,因为在OO中,唯一的公理是"everything is an object" . 因此,如今许多程序员往往不理解/欣赏/认识,因为他们已经被专门洗脑了"thinking the OO way" . 当值/不可变对象可能/通常会更好时,通常导致变量/可变对象像所有地方一样被使用 .
20
val表示不可变,var表示可变
你可以认为 val 为java编程语言 final 关键世界或c语言 const 关键世界 .
1
它就像它的名字一样简单 .
var意味着它可以改变val意味着不变
0
Val - 值是类型化存储常量 . 一旦创建,其值不能重新分配 . 可以使用关键字val定义新值 .
12 回答
虽然很多人已经回答了 Val 和 var 之间的区别 . 但有一点要注意的是 val is not exactly like final 关键字 .
我们可以使用递归来改变val的值,但是我们永远不能改变final的值 . 最终比Val更稳定 .
方法参数默认为val,并且每个调用值都在更改 .
Val
表示其 final ,不能 reassigned然而,
Var
可以是 reassigned later .正如许多其他人所说,分配给
val
的对象无法替换,并且分配给var
的对象可以 . 但是,所述对象可以修改其内部状态 . 例如:因此,即使我们无法更改分配给
x
的对象,我们也可以更改该对象的状态 . 然而,它的根源是var
.现在,由于许多原因,不变性是一件好事 . 首先,如果一个对象没有改变内部状态,你不必担心代码的其他部分是否正在改变它 . 例如:
对于多线程系统,这一点尤为重要 . 在多线程系统中,可能发生以下情况:
如果你只使用
val
,并且只使用不可变数据结构(也就是避免数组,scala.collection.mutable
中的所有内容等),你可以放心这会赢得一些代码,甚至是一个框架,做反射技巧 - 反射可以不幸的是,改变了"immutable"的值 .这是一个原因,但还有另一个原因 . 当您使用
var
时,您可能会尝试重复使用相同的var
用于多种用途 . 这有一些问题:阅读代码的人更难以知道代码的某个部分中变量的值是什么 .
您可能忘记在某些代码路径中重新初始化变量,并最终在代码中向下游传递错误的值 .
简而言之,使用
val
更安全,可以使代码更易读 .那么,我们可以走向另一个方向 . 如果
val
更好,为什么还要var
?好吧,有些语言确实采用了这种方式,但在某些情况下,可变性可以提高性能 .例如,采用不可变的
Queue
. 当你输入enqueue
或dequeue
时,你会得到一个新的Queue
对象 . 那你怎么去处理它里面的所有物品呢?我说你有一个数字队列,你想要用它们编写一个数字 . 例如,如果我有一个顺序为2,1,3的队列,我想要取回数字213.让我们先用_988465解决它:
此代码快速且易于理解 . 它的主要缺点是传递的队列被
toNum
修改,所以你必须事先复制它 . 这就是不变性让你摆脱的对象管理 .现在,让我们将其转换为
immutable.Queue
:因为我不能重用一些变量来跟踪我的
num
,就像在前面的例子中一样,我需要求助于递归 . 在这种情况下,它是一个尾递归,具有相当不错的性能 . 但情况并非总是如此:有时候没有好的(可读的,简单的)尾递归解决方案 .但请注意,我可以重写该代码以同时使用
immutable.Queue
和var
!例如:此代码仍然有效,不需要递归,在调用
toNum
之前,您无需担心是否必须复制队列 . 当然,我避免将变量重用于其他目的,并且此函数之外的代码都没有看到它们,所以我不需要担心它们的值从一行变为下一行 - 除非我明确这样做 .如果程序员认为程序员认为它是最好的解决方案,Scala选择让程序员这样做 . 其他语言选择使这些代码变得困难 . Scala(以及任何具有广泛可变性的语言)付出的代价是编译器在优化代码方面没有那么多的余地 . Java的答案是基于运行时配置文件优化代码 . 我们可以继续谈论各方的利弊 .
就个人而言,我认为斯卡拉目前正在取得适当的 balancer . 到目前为止,它并不完美 . 我认为Clojure和Haskell都有非常有趣的概念,Scala没有采用,但Scala也有自己的优势 . 我们将看到未来会发生什么 .
val
是最终的,也就是说,无法设置 . 想想java中的final
.简单来说:
var = var iable
val = v ariable fin al
不同之处在于
var
可以重新分配,而val
则不能 . 任何实际分配的可变性或其他方面都是一个副问题:鉴于:
因此:
如果要构建数据结构并且其所有字段都是
val
,则该数据结构因此是不可变的,因为其状态不能更改 .val
表示不可变,var
表示可变 .Full discussion.
从C的角度思考,
类似于指向非常数的常量指针数据
而
类似于非常量数据的非常量指针
支持
val
而不是var
增加了代码库的不变性,这可以促进其正确性,并发性和可理解性 .“val表示不可变,var表示可变 . ”
换句话说,“val表示值,var表示变量” .
在计算中恰好非常重要的区别(因为这两个概念定义了编程的本质),并且OO几乎完全模糊了,因为在OO中,唯一的公理是"everything is an object" . 因此,如今许多程序员往往不理解/欣赏/认识,因为他们已经被专门洗脑了"thinking the OO way" . 当值/不可变对象可能/通常会更好时,通常导致变量/可变对象像所有地方一样被使用 .
你可以认为
val
为java编程语言final
关键世界或c语言const
关键世界 .它就像它的名字一样简单 .
Val - 值是类型化存储常量 . 一旦创建,其值不能重新分配 . 可以使用关键字val定义新值 .
例如 . val x:Int = 5
此类型是可选的,因为scala可以从指定的值推断它 .
Var - 变量是类型化存储单元,只要保留存储空间,就可以再次为其分配值 .
例如 . var x:Int = 5
存储在两个存储单元中的数据在不再需要时由JVM自动解除分配 .
在scala中,值优先于变量,因为它们会给代码带来稳定性,特别是在并发和多线程代码中 .