329 votes

Quelle est la différence entre une définition var et val en Scala ?

Quelle est la différence entre un et définition de Scala et pourquoi la langue besoin des deux ? Pourquoi choisiriez-vous un sur un et vice versa ?

355voto

Daniel C. Sobral Points 159554

Comme beaucoup d'autres l'ont dit, l'objet affecté à un val ne peut pas être remplacé, et l'objet affecté à un var peut. Toutefois, l'objet peut avoir son état interne modifié. Par exemple:

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

Donc, même si nous ne pouvons pas changer l'objet assigné à l' x, nous pourrions changer l'état d'un objet. À la racine de celui-ci, cependant, il y avait un var.

Maintenant, l'immuabilité est une bonne chose pour beaucoup de raisons. Tout d'abord, si un objet ne change pas d'état interne, vous n'avez pas à vous inquiéter si une autre partie de votre code est en train de changer. Par exemple:

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

Cela devient particulièrement important avec multithread systèmes. Dans un multithread système, les situations suivantes peuvent se produire:

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

Si vous utilisez val exclusivement, et de n'utiliser immuable des structures de données (qui est, d'éviter les tableaux, tout en scala.collection.mutable, etc.), vous pouvez être assuré que cela n'arrivera pas. C'est, sauf s'il y a un peu de code, peut-être même un cadre, en faisant réflexion astuces -- réflexion peut changer "immuable" valeurs", malheureusement.

C'est une des raisons, mais il y a une autre raison pour cela. Lorsque vous utilisez var, vous pouvez être tenté en réutilisant le même var des fins multiples. Cela a quelques problèmes:

  • Il sera plus difficile pour les gens à lire le code pour savoir quelle est la valeur d'une variable dans une certaine partie du code.
  • Vous pouvez oublier de ré-initialiser la variable dans le code de chemin, et à la fin passant de mauvaises valeurs en aval dans le code.

Il suffit de mettre, à l'aide de val est plus sûr et conduit à un code plus lisible.

Nous pouvons, ensuite, aller dans l'autre direction. Si val qui est mieux, pourquoi avez - var ? Ainsi, certaines langues ne prendre cette route, mais il existe des situations dans lesquelles la mutabilité améliore les performances, beaucoup.

Par exemple, prendre un immuable Queue. Lorsque vous enqueue ou dequeue choses, vous obtenez un nouveau Queue objet. Comment, alors, vous allez sur le traitement de tous les éléments qu'il contient?

Je vais examiner cela avec un exemple. Disons que vous avez une file d'attente de chiffres, et vous souhaitez composer un numéro à l'intérieur d'eux. Par exemple, si j'ai une file d'attente avec 2, 1, 3, dans cet ordre, je veux revenir le numéro 213. Parlons tout d'abord de le résoudre avec un mutable.Queue:

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

Ce code est rapide et facile à comprendre. Son principal inconvénient est que la file d'attente qui est passé est modifié par toNum, de sorte que vous avez à faire une copie de celui-ci à l'avance. C'est le genre de gestion de l'objet que l'immutabilité vous rend libre de.

Maintenant, nous allons le convertir à 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)
}

Parce que je ne peux pas réutiliser une partie variable pour garder une trace de mon num, comme dans l'exemple précédent, j'ai besoin de recourir à la récursivité. Dans ce cas, c'est une queue-de récursivité, qui a assez de bonnes performances. Mais ce n'est pas toujours le cas: parfois, il n'est tout simplement pas bon (lisible, simple) la queue de la récursivité de la solution.

Notez, cependant, que je peux réécrire ce code pour utiliser un immutable.Queue et var à la même heure! Par exemple:

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
}

Ce code est toujours efficace, ne nécessite pas la récursivité, et vous n'avez pas besoin de vous inquiéter de savoir si vous devez faire une copie de votre file d'attente ou pas, avant d'appeler toNum. Naturellement, j'ai évité la réutilisation des variables pour d'autres fins, et pas de code en dehors de cette fonction les voit, donc je n'ai pas besoin de vous soucier de leur évolution des valeurs d'une ligne à l'autre-sauf que quand j'ai explicitement de le faire.

Scala a opté pour permettre au programmeur de le faire, si le programmeur réputée pour être la meilleure solution. D'autres langues ont choisi de rendre le code difficile. Le prix de la Scala (et de n'importe quelle langue avec une généralisation de la mutabilité) paie est que le compilateur n'a pas autant de marge de manœuvre dans l'optimisation du code, comme pourrait le contraire. Java est la réponse qui est l'optimisation du code sur la base de l'exécution du profil. Nous pourrions continuer encore et encore sur les avantages et les inconvénients de chaque côté.

Personnellement, je pense que Scala le bon équilibre, pour l'instant. Il n'est pas parfait, et de loin. Je pense que les deux Clojure et Haskell ont des notions très intéressantes non adopté par l'Scala, mais Scala a ses propres points forts. Nous allons voir ce qui arrive sur l'avenir.

63voto

Jackson Davis Points 1518

Certes, c’est, ne peut pas être définie. Pense que en java.

22voto

Stefan Kendall Points 28274

moyens immuables et moyens mutables.

Examen approfondi.

22voto

oxbow_lakes Points 70013

La différence est qu’un peut être réaffecté à alors qu’un ne peut pas. La mutabilité, ou autrement, de tout ce qui est réellement affecté, est une question secondaire :

Considérant que :

Et donc :

Si vous créez une structure de données et tous ses champs sont `` s, alors que cette structure de données est donc immuable, car son état ne peut pas changer.

10voto

Erwin Smout Points 7499

"val signifie immuable et var moyens mutable."

Pour paraphraser, "val moyen de la valeur et du var moyens variable".

Une distinction qui se trouve être extrêmement important dans le calcul (car ces deux concepts définissent l'essence même de ce que la programmation est tout au sujet), et que OO a réussi à le flou presque complètement, parce que dans OO, le seul axiome est que "tout est un objet". Et que, par conséquent, beaucoup de programmeurs ces jours-ci ont tendance à ne pas comprendre/apprécier/reconnaître, parce qu'ils ont été endoctrinés dans "penser l'OO façon" exclusivement. Aboutissant souvent à une variable/mutable objets utilisés comme partout, lorsque la valeur des objets immuables pourrait/aurait été mieux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X