¿Cuál es la diferencia entre una definición var y val en Scala?


¿Cuál es la diferencia entre una definición var y val en Scala y por qué el lenguaje necesita ambas? ¿Por qué elegirías un val sobre un var y viceversa?

 272
Author: Derek Mahar, 2009-11-24

13 answers

Como muchos otros han dicho, el objeto asignado a un val no puede ser reemplazado, y el objeto asignado a un var puede. Sin embargo, dicho objeto puede tener su estado interno modificado. Por ejemplo:

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

Así que, aunque no podamos cambiar el objeto asignado a x, podríamos cambiar el estado de ese objeto. En la raíz de ella, sin embargo, había un var.

Ahora bien, la inmutabilidad es algo bueno por muchas razones. Primero, si un objeto no cambia el estado interno, no tienes que preocuparte si alguna otra parte de tu código lo está cambiando. Por ejemplo:

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

Esto se vuelve particularmente importante con sistemas multihilo. En un sistema multiproceso, puede ocurrir lo siguiente:

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

Si usa val exclusivamente, y solo use estructuras de datos inmutables (es decir, evite arrays, todo en scala.collection.mutable, etc.), puede estar seguro de que esto no sucederá. Es decir, a menos que haya algún código, tal vez incluso un marco, haciendo trucos de reflexión can la reflexión puede cambiar los valores "inmutables", por desgracia.

Esa es una razón, pero hay otra razón para ello. Cuando usas var, puedes ser tentado a reutilizar el mismo var para múltiples propósitos. Esto tiene algunos problemas:

  • Será más difícil para las personas que leen el código saber cuál es el valor de una variable en una cierta parte del código.
  • Puede olvidarse de volver a inicializar la variable en alguna ruta de código, y terminar pasando valores incorrectos codificar.

En pocas palabras, usar val es más seguro y conduce a un código más legible.

Podemos, entonces, ir en la otra dirección. Si val es eso mejor, ¿por qué tener var en absoluto? Bueno, algunos idiomas tomaron esa ruta, pero hay situaciones en las que la mutabilidad mejora el rendimiento, mucho.

Por ejemplo, tomemos un Queue inmutable. Cuando ya sea enqueue o dequeue cosas en él, se obtiene un nuevo objeto Queue. ¿Cómo entonces, irías sobre el procesamiento de todos los elementos en ¿eso?

Voy a ir a través de eso con un ejemplo. Digamos que tienes una cola de dígitos, y quieres componer un número de ellos. Por ejemplo, si tengo una cola con 2, 1, 3, en ese orden, quiero recuperar el número 213. Primero vamos a resolverlo con un mutable.Queue:

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

Este código es rápido y fácil de entender. Su principal inconveniente es que la cola que se pasa es modificada por toNum, por lo que debe hacer una copia de ella de antemano. Ese es el tipo de gestión de objetos que la inmutabilidad te libera de.

Ahora, vamos a convertirlo en un 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)
}

Debido a que no puedo reutilizar alguna variable para realizar un seguimiento de mi num, como en el ejemplo anterior, necesito recurrir a la recursión. En este caso, es una recursión de cola, que tiene un rendimiento bastante bueno. Pero ese no es siempre el caso: a veces simplemente no hay una solución de recursión de cola buena (legible, simple).

Tenga en cuenta, sin embargo, que puedo reescribir ese código para usar un immutable.Queue y un var en el mismo tiempo! Por ejemplo:

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
}

Este código sigue siendo eficiente, no requiere recursividad, y no necesita preocuparse si tiene que hacer una copia de su cola o no antes de llamar a toNum. Naturalmente, evité reutilizar variables para otros propósitos, y ningún código fuera de esta función las ve, así que no necesito preocuparme por sus valores cambiando de una línea a la siguiente except excepto cuando lo hago explícitamente.

Scala optó por dejar que el programador haga eso, si el programador consideró que era la mejor solución. Otros idiomas han optado por dificultar dicho código. El precio que paga Scala (y cualquier lenguaje con mutabilidad generalizada) es que el compilador no tiene tanto margen para optimizar el código como podría hacerlo de otra manera. La respuesta de Java a eso es optimizar el código basado en el perfil de tiempo de ejecución. Podríamos seguir y seguir sobre los pros y los contras de cada lado.

Personalmente, creo que Scala encuentra el equilibrio correcto, por ahora. No es perfecto, de lejos. Creo que tantoClojure comoHaskell tienen nociones muy interesantes no adoptadas por Scala, pero Scala también tiene sus propias fortalezas. Veremos lo que viene en el futuro.

 302
Author: Daniel C. Sobral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-24 18:27:48

val es definitivo, es decir, no se puede fijar. Piensa final en java.

 55
Author: Jackson Davis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-24 17:23:38

En términos simples:

Var = variable

Val = variable + aletaal

 41
Author: Ajay Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-01 17:11:17

La diferencia es que a var se puede reasignar mientras que a val no. La mutabilidad, o no, de lo que realmente se asigna, es un problema secundario:

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.

Considerando lo siguiente:

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

Y por lo tanto:

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

Si está construyendo una estructura de datos y todos sus campos son vals, entonces esa estructura de datos es inmutable, ya que su estado no puede cambiar.

 20
Author: oxbow_lakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-24 18:30:03

val significa inmutable y var significa mutable.

Discusión Completa.

 19
Author: Stefan Kendall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-24 16:58:39

Pensando en términos de C++,

val x: T

Es análogo al puntero constante a datos no constantes

T* const x;

Mientras que

var x: T 

Es análogo al puntero no constante a datos no constantes

T* x;

Favorecer val sobre var aumenta la inmutabilidad del código base que puede facilitar su corrección, concurrencia y comprensibilidad.

 11
Author: Mario Galic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-16 21:04:14

"val significa inmutable y var significa mutable."

Parafraseando, "val significa valor y var significa variable".

Una distinción que resulta extremadamente importante en computación (porque esos dos conceptos definen la esencia misma de lo que se trata la programación), y que OO ha logrado difuminar casi por completo, porque en OO, el único axioma es que "todo es un objeto". Y que como consecuencia, muchos programadores en estos días tienden a no entender / apreciar / reconocer, porque se les ha lavado el cerebro para que "piensen de la manera OO" exclusivamente. A menudo conduce a objetos variables / mutables que se usan como en todas partes, cuando los objetos de valor/inmutables podrían/a menudo habrían sido mejores.

 8
Author: Erwin Smout,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-24 17:33:53

Val significa inmutable y var significa mutable

Puedes pensar val como lenguaje de programación java final mundo clave o lenguaje c++ const mundo clave。

 6
Author: Rollen Holt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-07 09:50:18

A val es similar a una variable final en Java. Una vez inicializado, un val nunca puede ser reasignado.

A var, por el contrario, es similar a una variable no final en Java. A var puede ser reasignado a lo largo de su vida.

 2
Author: Amine Sagaama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-05 22:11:34

Es tan simple como su nombre.

Var significa que puede variar

Val significa invariable

 1
Author: user105003,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-27 19:29:41

Los valores Val son constantes de almacenamiento escritas. Una vez creado su valor no puede ser reasignado. se puede definir un nuevo valor con la palabra clave val.

Eg. val x: Int = 5

Aquí el tipo es opcional ya que scala puede inferirlo del valor asignado.

Las variables var son unidades de almacenamiento tipificadas a las que se les pueden asignar valores de nuevo siempre que se reserve espacio de memoria.

Eg. var x: Int = 5

Los datos almacenados en ambas unidades de almacenamiento son automáticamente desasignados por JVM una vez estos ya no son necesarios.

En scala, los valores son preferibles a las variables debido a la estabilidad que aportan al código, particularmente en código concurrente y multiproceso.

 0
Author: SunTech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-19 16:31:42

Aunque muchos ya han respondido a la diferencia entre Val y var. Pero un punto a notar es que val no es exactamente como la palabra clave final.

Podemos cambiar el valor de val usando recursión pero nunca podemos cambiar el valor de final. Final es más constante que Val.

def factorial(num: Int): Int = {
 if(num == 0) 1
 else factorial(num - 1) * num
}

Los parámetros del método son por defecto val y en cada valor de llamada se cambia.

 0
Author: Mahesh Chand Kandpal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-18 07:38:04

Val significa su final , no puede ser reasignado

Considerando que, Var puede ser reasignado más tarde.

 0
Author: Crime_Master_GoGo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-11 19:31:07