Scala中的var和val定义有什么区别?

Scala中的varval定义有什么不同?语言为什么需要这两者? 为什么你会select一个val ,反之亦然?

正如许多其他人所说,分配给val的对象不能被replace,而分配给var的对象可以被replace。 但是,所述对象可以修改其内部状态。 例如:

 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

现在,不变性是一件好事,原因很多。 首先,如果一个对象不改变内部状态,你不必担心你的代码的其他部分是否正在改变它。 例如:

 x = new B(0) f(x) if (x.value.value == 0) println("f didn't do anything to x") else println("f did something to x") 

multithreading系统对此变得尤为重要。 在multithreading系统中,可能会发生以下情况:

 x = new B(1) f(x) if (x.value.value == 1) { print(x.value.value) // Can be different than 1! } 

如果你只使用val ,并且只使用不可变的数据结构(即避免数组, scala.collection.mutable所有内容等),那么你可以放心,这是不会发生的。 也就是说,除非有一些代码,甚至可能是一个框架,做reflection技巧 – 不幸的是reflection会改变“不可变的”值。

这是一个原因,但是还有另一个原因。 当你使用var ,你可以试图重复使用同一个var来达到多种目的。 这有一些问题:

  • 阅读代码的人会更难以知道代码某个部分的variables的价值。
  • 您可能忘记在某些代码path中重新初始化variables,并最终在代码中传递错误的值。

简而言之,使用val更安全,并导致更易读的代码。

那么我们可以走向另一个方向。 如果val更好,为什么有var ? 那么,一些语言确实采取了这样的路线,但有些情况下,可变性提高了性能,很多。

例如,采取一个不可变的Queue 。 当你入enqueuedequeue时,你会得到一个新的Queue对象。 那么怎么样,你会去处理它的所有项目?

我将以一个例子来说明这一点。 假设你有一个数字队列,你想要编写一个数字。 例如,如果我有一个mutable.Queue的队列,那么我要回到213.让我们首先用一个mutable.Queue解决它:

 def toNum(q: scala.collection.mutable.Queue[Int]) = { var num = 0 while (!q.isEmpty) { num *= 10 num += q.dequeue } num } 

此代码速度快,易于理解。 它的主要缺点是传递的队列被toNum修改,所以你必须事先做一个拷贝。 这是不变性使你从中解脱出来的那种对象pipe理。

现在,让我们把它变成一个immutable.Queue

 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) } 

因为我不能重用一些variables来跟踪我的num ,就像在前面的例子中,我需要诉诸recursion。 在这种情况下,它是一个尾recursion,性能相当不错。 但情况并非总是如此:有时候没有好的(可读的,简单的)尾recursion解决scheme。

但是,请注意,我可以重写该代码以同时使用immutable.Queuevar ! 例如:

 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 } 

此代码仍然有效,不需要recursion,在调用toNum之前,您不必担心是否必须复制队列。 当然,我避免将variables用于其他目的,除此之外的任何代码都不会看到它们,所以我不必担心它们的值从一行变到另一行 – 除非我明确这样做。

如果程序员认为它是最好的解决scheme,Scalaselect让程序员这样做。 其他语言select使这样的代码困难。 价格Scala(以及任何具有普遍可变性的语言)都付出代价,即编译器在优化代码方面没有那么好。 Java的答案是根据运行时configuration文件优化代码。 我们可以继续谈论每一方的利弊。

就我个人而言,现在我认为Scala达到了平衡。 到目前为止,这并不完美。 我认为Clojure和Haskell都有一些Scala没有采用的非常有趣的概念,但是Scala也有自己的优势。 我们将看到未来会发生什么。

val是final的,也就是说不能设置。 在Java中考虑final

简单来说:

var = variable

val = va riable + fin al

val表示不可变, var表示可变。

充分讨论。

不同之处在于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. 

如果你正在构build一个数据结构并且它的所有字段都是val ,那么这个数据结构是不可变的,因为它的状态不能改变。

用C ++来思考,

 val x: T 

类似于指向非常量数据的常量指针

 T* const x; 

 var x: T 

类似于对非常数数据的非常量指针

 T* x; 

valval支持增加了代码库的不变性,这可以促进它的正确性,并发性和可理解性。

“val意味着不可变,var意味着可变。”

换句话说,“val意味着价值和var意味着variables”。

这个区别在计算中是非常重要的(因为这两个概念定义了编程的本质),而且OO几乎完全模糊了,因为在OO中,唯一的公理是“一切都是目的”。 因此,现在很多程序员往往不理解/欣赏/认可,因为他们被洗脑成为“专心思考OO方式”。 通常会导致variables/可变对象像所有地方一样被使用,当值/不可变对象可能/往往会更好。

val表示不可变,var表示可变

你可以把val看作是java编程语言final关键世界或者c ++语言的const关键世界。

val类似于Java中的最终variables。 一旦初始化, val就不能被重新分配。

相比之下, var类似于Java中的非finalvariables。 var可以在整个生命周期中重新分配。

这就像它的名字一样简单。

var意味着它可以变化

val意思是不变的

Val值是键入的存储常量。 一旦创build它的价值不能被重新分配。 一个新的值可以用关键字val定义。

例如。 val x:Int = 5

这里的types是可选的,因为scala可以从分配的值中推断出来。

Var – variables是types化的存储单元,只要内存空间被保留,可以重新赋值。

例如。 var x:Int = 5

存储在两个存储单元中的数据一旦被不再需要,就会被JVM自动解除分配。

在scala中,由于这些代码带来的稳定性,尤其是在并发和multithreading代码中,所以值优于variables。