Recherche…


Remarques

Les noms de valeur et de variable doivent être en cas de chameau inférieur

Les noms constants doivent être en cas de chameau supérieur. Autrement dit, si le membre est final, immuable et qu’il appartient à un objet ou à un objet, il peut être considéré comme une constante

La méthode, la valeur et les noms de variables doivent être dans le cas camel inférieur

Source: http://docs.scala-lang.org/style/naming-conventions.html

Cette compilation:

val (a,b) = (1,2)
// a: Int = 1
// b: Int = 2

mais ce n'est pas le cas:

val (A,B) = (1,2)
// error: not found: value A
// error: not found: value B

Ce n'est pas juste val vs var

val et var

scala> val a = 123
a: Int = 123

scala> a = 456
<console>:8: error: reassignment to val
       a = 456

scala> var b = 123
b: Int = 123

scala> b = 321
b: Int = 321
  • val références val sont inchangeables: comme une variable final en Java , une fois initialisée, vous ne pouvez plus la changer
  • var références var peuvent être réaffectées en tant que déclaration de variable simple en Java

Collections immuables et Mutable

  val mut = scala.collection.mutable.Map.empty[String, Int]
  mut += ("123" -> 123)
  mut += ("456" -> 456)
  mut += ("789" -> 789)

  val imm = scala.collection.immutable.Map.empty[String, Int]
  imm + ("123" -> 123)
  imm + ("456" -> 456)
  imm + ("789" -> 789)

  scala> mut
    Map(123 -> 123, 456 -> 456, 789 -> 789)

  scala> imm
    Map()

scala> imm + ("123" -> 123) + ("456" -> 456) + ("789" -> 789)
    Map(123 -> 123, 456 -> 456, 789 -> 789)

La bibliothèque standard Scala offre à la fois des structures de données immuables et mutables, et non la référence à celle-ci. Chaque fois qu'une structure de données immuable est "modifiée", une nouvelle instance est produite au lieu de modifier la collection d'origine sur place. Chaque instance de la collection peut partager une structure significative avec une autre instance.

Collection Mutable et Immuable (Documentation Scala Officielle)

Mais je ne peux pas utiliser l'immuabilité dans ce cas!

Prenons comme exemple une fonction qui prend 2 Map et renvoie une Map contenant tous les éléments de ma et mb :

def merge2Maps(ma: Map[String, Int], mb: Map[String, Int]): Map[String, Int]

Une première tentative pourrait être une itération à travers les éléments d'une des cartes en utilisant for ((k, v) <- map) et renvoyer d'une manière ou d'une autre la carte fusionnée.

def merge2Maps(ma: ..., mb: ...): Map[String, Int] = {

  for ((k, v) <- mb) {
    ???
  }

}

Ce tout premier pas ajoute immédiatement une contrainte: une mutation en dehors de celle for est maintenant nécessaire . Ceci est plus clair lors de la suppression du sucre for :

// this:
for ((k, v) <- map) { ??? }

// is equivalent to:
map.foreach { case (k, v) => ??? }

"Pourquoi devons-nous muter?"

foreach repose sur les effets secondaires. Chaque fois que nous voulons que quelque chose se produise dans un foreach nous devons "modifier quelque chose", dans ce cas nous pourrions muter un var result variable ou utiliser une structure de données mutable.

Créer et remplir la carte de result

Supposons que ma et mb sont scala.collection.immutable.Map , nous pourrions créer le result Map de ma :

val result = mutable.Map() ++ ma

Ensuite, parcourez mb ajoutant ses éléments et si la key de l'élément actuel sur ma existe déjà, passons à celle de l'élément mb .

mb.foreach { case (k, v) => result += (k -> v) }

Implémentation Mutable

Jusqu'ici tout va bien, nous avons "dû utiliser des collections mutables" et une implémentation correcte pourrait être:

def merge2Maps(ma: Map[String, Int], mb: Map[String, Int]): Map[String, Int] = {
  val result = scala.collection.mutable.Map() ++ ma
  mb.foreach { case (k, v) => result += (k -> v) }
  result.toMap // to get back an immutable Map
}

Comme prévu:

scala> merge2Maps(Map("a" -> 11, "b" -> 12), Map("b" -> 22, "c" -> 23))
  Map(a -> 11, b -> 22, c -> 23)

Se plier à la rescousse

Comment pouvons-nous nous débarrasser de foreach dans ce scénario? Si tout ce que nous faisons est essentiellement itératif sur les éléments de la collection et appliquer une fonction tout en accumulant le résultat, l'option pourrait utiliser .foldLeft :

def merge2Maps(ma: Map[String, Int], mb: Map[String, Int]): Map[String, Int] = {
  mb.foldLeft(ma) { case (result, (k, v)) => result + (k -> v) }
  // or more concisely mb.foldLeft(ma) { _ + _ }
}

Dans ce cas, notre "résultat" est la valeur accumulée à partir de ma , le zero du .foldLeft .

Résultat intermédiaire

Evidemment, cette solution immuable produit et détruit de nombreuses instances de la Map lors du pliage, mais il convient de mentionner que ces instances ne sont pas un clone complet de la Map accumulée mais partagent une structure (données) importante avec l'instance existante.

Facilité de raisonnement

Il est plus facile de raisonner sur la sémantique si elle est plus déclarative que l’approche .foldLeft . L'utilisation de structures de données immuables pourrait contribuer à simplifier notre implémentation.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow