¿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?
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.
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.
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
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 val
s, entonces esa estructura de datos es inmutable, ya que su estado no puede cambiar.
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.
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.
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.
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。
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.
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
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.
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.
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.
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