Buscar..


Observaciones

Los nombres de valores y variables deben estar en la caja inferior del camello

Los nombres constantes deben estar en la caja superior del camello. Es decir, si el miembro es definitivo, inmutable y pertenece a un objeto de paquete o un objeto, puede considerarse una constante

El método, el valor y los nombres de las variables deben estar en la caja inferior del camello

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

Esta compilación:

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

pero esto no lo hace

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

No es solo val vs. var.

val y 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 referencias val son inmutables: como una variable final en Java , una vez que se ha inicializado no se puede cambiar
  • var referencias var son reasignables como una simple declaración de variable en Java

Colecciones inmutables y mutables.

  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 biblioteca estándar de Scala ofrece estructuras de datos inmutables y mutables, no la referencia a ella. Cada vez que una estructura de datos inmutables se "modifica", se produce una nueva instancia en lugar de modificar la colección original en el lugar. Cada instancia de la colección puede compartir una estructura significativa con otra instancia.

Colección mutable e inmutable (Documentación Oficial Scala)

¡Pero no puedo usar la inmutabilidad en este caso!

Tomemos como ejemplo una función que toma 2 Map y devolvemos un Map contiene cada elemento en ma y mb :

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

Un primer intento podría ser iterar a través de los elementos de uno de los mapas usando for ((k, v) <- map) y de alguna manera devolver el mapa combinado.

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

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

}

Este primer movimiento agrega inmediatamente una restricción: ahora se necesita una mutación fuera de la misma for . Esto es más claro cuando se elimina el azúcar for :

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

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

"¿Por qué tenemos que mutar?"

foreach basa en los efectos secundarios. Cada vez que queremos que algo suceda dentro de un foreach necesitamos "efectos secundarios", en este caso podríamos mutar un var result variable var result o podemos usar una estructura de datos mutable.

Creando y rellenando el mapa de result

Supongamos que ma y mb son scala.collection.immutable.Map , podríamos crear el Mapa de result de ma :

val result = mutable.Map() ++ ma

Luego itere a través de mb agregando sus elementos y si la key del elemento actual en ma ya existe, anulémosla con mb one.

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

Implementación mutable

Hasta ahora todo bien, "tuvimos que usar colecciones mutables" y una implementación correcta podría ser:

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
}

Como se esperaba:

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

Plegado al rescate.

¿Cómo podemos deshacernos de foreach en este escenario? Si lo único que debemos hacer es iterar básicamente sobre los elementos de la colección y aplicar una función mientras se acumula el resultado en la opción, podría estar usando .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) { _ + _ }
}

En este caso, nuestro "resultado" es el valor acumulado a partir de ma , el zero de .foldLeft .

Resultado intermedio

Obviamente, esta solución inmutable produce y destruye muchas instancias del Map mientras se pliega, pero vale la pena mencionar que esas instancias no son un clon completo del Map acumulado, sino que comparten una estructura significativa (datos) con la instancia existente.

Razonabilidad más fácil

Es más fácil razonar acerca de la semántica si es más declarativo como el enfoque .foldLeft . El uso de estructuras de datos inmutables podría ayudar a hacer que nuestra implementación sea más fácil de razonar.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow