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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1791408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:45:39  来源:igfitidea点击:

What is the difference between a var and val definition in Scala?

scala

提问by Derek Mahar

What is the difference between a varand valdefinition in Scala and why does the language need both? Why would you choose a valover a varand vice versa?

Scala 中的avarval定义之间有什么区别,为什么该语言需要两者?为什么你会选择a而val不是a var,反之亦然?

回答by Daniel C. Sobral

As so many others have said, the object assigned to a valcannot be replaced, and the object assigned to a varcan. However, said object can have its internal state modified. For example:

正如许多其他人所说,分配给 a 的对象val无法替换,分配给 a 的对象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.
  }
}

So, even though we can't change the object assigned to x, we could change the state of that object. At the root of it, however, there was a var.

因此,即使我们无法更改分配给 的对象x,我们也可以更改该对象的状态。然而,在它的根源,有一个var.

Now, immutability is a good thing for many reasons. First, if an object doesn't change internal state, you don't have to worry if some other part of your code is changing it. For example:

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

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

This becomes particularly important with multithreaded systems. In a multithreaded system, the following can happen:

这对于多线程系统变得尤为重要。在多线程系统中,可能会发生以下情况:

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

If you use valexclusively, and only use immutable data structures (that is, avoid arrays, everything in scala.collection.mutable, etc.), you can rest assured this won't happen. That is, unless there's some code, perhaps even a framework, doing reflection tricks -- reflection can change "immutable" values, unfortunately.

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

That's one reason, but there is another reason for it. When you use var, you can be tempted into reusing the same varfor multiple purposes. This has some problems:

这是一个原因,但还有另一个原因。当您使用 时var,您可能会var出于多种目的重复使用相同的内容。这有一些问题:

  • It will be more difficult for people reading the code to know what is the value of a variable in a certain part of the code.
  • You may forget to re-initialize the variable in some code path, and end up passing wrong values downstream in the code.
  • 阅读代码的人更难知道代码的某个部分中变量的值是什么。
  • 您可能忘记在某些代码路径中重新初始化变量,并最终在代码中向下游传递错误的值。

Simply put, using valis safer and leads to more readable code.

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

We can, then, go the other direction. If valis that better, why have varat all? Well, some languages did take that route, but there are situations in which mutability improves performance, a lot.

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

For example, take an immutable Queue. When you either enqueueor dequeuethings in it, you get a new Queueobject. How then, would you go about processing all items in it?

例如,采用一个不可变的Queue. 当你enqueue或者里面的dequeue东西时,你会得到一个新的Queue对象。那么,您会如何处理其中的所有项目?

I'll go through that with an example. Let's say you have a queue of digits, and you want to compose a number out of them. For example, if I have a queue with 2, 1, 3, in that order, I want to get back the number 213. Let's first solve it with a mutable.Queue:

我将通过一个例子来说明。假设您有一个数字队列,并且您想从中组合一个数字。例如,如果我有一个按 2, 1, 3 的顺序排列的队列,我想取回数字 213。让我们先用 a 解决它mutable.Queue

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

This code is fast and easy to understand. Its main drawback is that the queue that is passed is modified by toNum, so you have to make a copy of it beforehand. That's the kind of object management that immutability makes you free from.

此代码快速且易于理解。它的主要缺点是传递的队列被 修改toNum,因此您必须事先制作它的副本。这就是不变性使您摆脱的那种对象管理。

Now, let's covert it to an immutable.Queue:

现在,让我们将其转换为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)
}

Because I can't reuse some variable to keep track of my num, like in the previous example, I need to resort to recursion. In this case, it is a tail-recursion, which has pretty good performance. But that is not always the case: sometimes there is just no good (readable, simple) tail recursion solution.

因为我不能重用一些变量来跟踪我的num,就像在前面的例子中一样,我需要求助于递归。在这种情况下,它是一个尾递归,具有相当好的性能。但情况并非总是如此:有时只是没有好的(可读的、简单的)尾递归解决方案。

Note, however, that I can rewrite that code to use an immutable.Queueand a varat the same time! For example:

但是请注意,我可以重写该代码以同时使用 animmutable.Queue和 a 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
}

This code is still efficient, does not require recursion, and you don't need to worry whether you have to make a copy of your queue or not before calling toNum. Naturally, I avoided reusing variables for other purposes, and no code outside this function sees them, so I don't need to worry about their values changing from one line to the next -- except when I explicitly do so.

这段代码仍然有效,不需要递归,并且您不必担心在调用toNum. 自然地,我避免将变量重用用于其他目的,并且此函数之外的任何代码都看不到它们,所以我不需要担心它们的值从一行更改为下一行——除非我明确这样做。

Scala opted to let the programmer do that, if the programmer deemed it to be the best solution. Other languages have chosen to make such code difficult. The price Scala (and any language with widespread mutability) pays is that the compiler doesn't have as much leeway in optimizing the code as it could otherwise. Java's answer to that is optimizing the code based on the run-time profile. We could go on and on about pros and cons to each side.

如果程序员认为这是最好的解决方案,Scala 会选择让程序员这样做。其他语言选择使此类代码变得困难。Scala(以及任何具有广泛可变性的语言)所付出的代价是编译器在优化代码方面没有那么多余地。Java 对此的回答是根据运行时配置文件优化代码。我们可以继续讨论每一方的利弊。

Personally, I think Scala strikes the right balance, for now. It is not perfect, by far. I think both Clojureand Haskellhave very interesting notions not adopted by Scala, but Scala has its own strengths as well. We'll see what comes up on the future.

就我个人而言,我认为 Scala 目前取得了正确的平衡。到目前为止,它并不完美。我认为ClojureHaskell都有 Scala 没有采用的非常有趣的概念,但 Scala 也有自己的优势。我们将看看未来会发生什么。

回答by Hymanson Davis

valis final, that is, cannot be set. Think finalin java.

val是最终的,即不能设置。final在java中思考。

回答by Ajay Gupta

In simple terms:

简单来说:

var= variable

VAR= VARiable

val= variable + final

VAL= v良莠不齐+鳍

回答by oxbow_lakes

The difference is that a varcan be re-assigned to whereas a valcannot. The mutability, or otherwise of whatever is actually assigned, is a side issue:

区别在于 avar可以重新分配,而 aval不能。实际分配的任何内容的可变性或其他方式是一个附带问题:

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.

Whereas:

然而:

val n = immutable.Set("London", "Paris")
n = immutable.Set("New York") //Will not compile as n is a val.

And hence:

因此:

val n = mutable.Set("London", "Paris")
n = mutable.Set("New York") //Will not compile, even though the type of n is mutable.

If you are building a data structure and all of its fields are vals, then that data structure is therefore immutable, as its state cannot change.

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

回答by Stefan Kendall

valmeans immutable and varmeans mutable.

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

Full discussion.

充分讨论。

回答by Mario Galic

Thinking in terms of C++,

从 C++ 的角度思考,

val x: T

is analogous to constant pointer to non-constant data

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

T* const x;

while

尽管

var x: T 

is analogous to non-constant pointer to non-constant data

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

T* x;

Favoring valover varincreases immutability of the codebase which can facilitate its correctness, concurrency and understandability.

有利于valvar增加,可促进其正确性,并发性和可理解的代码库的不变性。

To understand the meaning of having a constant pointer to non-constant data consider the following Scala snippet:

要理解具有指向非常量数据的常量指针的含义,请考虑以下 Scala 片段:

val m = scala.collection.mutable.Map(1 -> "picard")
m // res0: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard)

Here the "pointer"val mis constant so we cannot re-assign it to point to something else like so

这里的“指针”val m是常量,所以我们不能重新分配它来指向其他类似的东西

m = n // error: reassignment to val

however we can indeed change the non-constant data itself that mpoints to like so

然而我们确实可以改变m指向像这样的非常量数据本身

m.put(2, "worf")
m // res1: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard, 2 -> worf)

回答by Erwin Smout

"val means immutable and var means mutable."

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

To paraphrase, "val means value and var means variable".

套用一句,“val 表示值,var 表示变量”。

A distinction that happens to be extremely important in computing (because those two concepts define the very essence of what programming is all about), and that OO has managed to blur almost completely, because in OO, the only axiom is that "everything is an object". And that as a consequence, lots of programmers these days tend not to understand/appreciate/recognize, because they have been brainwashed into "thinking the OO way" exclusively. Often leading to variable/mutable objects being used like everywhere, when value/immutable objects might/would often have been better.

恰好在计算中非常重要的一个区别(因为这两个概念定义了编程的本质),并且 OO 几乎完全模糊了,因为在 OO 中,唯一的公理是“一切都是一个目的”。因此,如今许多程序员往往不理解/欣赏/认识,因为他们已经被洗脑,专门“以面向对象的方式思考”。通常会导致变量/可变对象像无处不在一样被使用,而值/不可变对象可能/通常会更好。

回答by Rollen Holt

val means immutable and var means mutable

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

you can think valas java programming language finalkey world or c++ language constkey world。

你可以认为val是java编程语言的final关键世界或c++语言的const关键世界。

回答by Crime_Master_GoGo

Valmeans its final, cannot be reassigned

Val意味着它的最终,不能重新分配

Whereas, Varcan be reassigned later.

而,Var可以稍后重新分配

回答by user105003

It's as simple as it name.

就像它的名字一样简单。

var means it can vary

val means invariable

var 意味着它可以变化

val 表示不变