Zoeken…


Opmerkingen

Waarde- en variabelenamen moeten in het onderste kameelgeval staan

Namen van constanten moeten in hoofdletters zijn. Dat wil zeggen, als het lid definitief is, onveranderlijk en het behoort tot een pakketobject of een object, kan het als een constante worden beschouwd

Naam van methode, waarde en variabele moet in het onderste kameelgeval staan

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

Deze compilatie:

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

maar dit doet niet:

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

Het is niet alleen val vs. var

val en 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 verwijzingen zijn onveranderlijk: net als een final variabele in Java , kunt u deze niet meer wijzigen nadat deze is geïnitialiseerd
  • var referenties kunnen opnieuw worden toegewezen als een eenvoudige variabele-declaratie in Java

Onveranderlijke en veranderlijke collecties

  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)

De standaardbibliotheek van Scala biedt zowel onveranderlijke als veranderlijke datastructuren, niet de verwijzing ernaar. Elke keer dat een onveranderlijke datastructuur "gemodificeerd" wordt, wordt een nieuwe instantie geproduceerd in plaats van de oorspronkelijke verzameling ter plekke te wijzigen. Elke instantie van de collectie kan een belangrijke structuur delen met een andere instantie.

Mutabele en onveranderlijke verzameling (officiële Scala-documentatie)

Maar ik kan in dit geval geen onveranderlijkheid gebruiken!

Laten we als voorbeeld een functie kiezen die 2 Map en een Map retourneren die elk element in ma en mb :

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

Een eerste poging zou kunnen zijn om de elementen van een van de kaarten te doorlopen met behulp for ((k, v) <- map) en op de een of andere manier de samengevoegde kaart terug te geven.

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

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

}

Deze eerste zet onmiddellijk voeg een inperken: een mutatie buiten die for nu nodig is. Dit is duidelijker bij het ontdoen van de for :

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

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

"Waarom moeten we muteren?"

foreach vertrouwt op bijwerkingen. Elke keer als we iets binnen een foreach willen laten gebeuren, moeten we "neveneffecten", in dit geval kunnen we een variabel var result muteren of we kunnen een veranderlijke gegevensstructuur gebruiken.

De result en vullen

Laten we aannemen dat ma en mb scala.collection.immutable.Map , we kunnen het result Map van ma :

val result = mutable.Map() ++ ma

Herhaal vervolgens door mb de elementen toe te voegen en als de key van het huidige element op ma al bestaat, laten we deze vervangen door de mb key .

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

Mutabele implementatie

Tot dusver zo goed, moesten we "veranderlijke collecties gebruiken" en een correcte implementatie zou kunnen zijn:

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
}

Zoals verwacht:

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

Vouwen te hulp

Hoe kunnen we in dit scenario van foreach afkomen? Als alles wat we moeten doen in feite de collectie-elementen herhalen en een functie toepassen terwijl het resultaat op optie wordt verzameld, zou .foldLeft kunnen worden gebruikt:

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) { _ + _ }
}

In dit geval is ons "resultaat" de geaccumuleerde waarde die begint met ma , de zero van de .foldLeft .

Gemiddeld resultaat

Het is duidelijk dat deze onveranderlijke oplossing veel Map instanties produceert en vernietigt tijdens het vouwen, maar het is vermeldenswaard dat die instanties geen volledige kloon van de verzamelde Map , maar in plaats daarvan een aanzienlijke structuur (gegevens) delen met de bestaande instantie.

Gemakkelijkere redelijkheid

Het is gemakkelijker om over de semantiek te redeneren als deze meer declaratief is dan de .foldLeft benadering. Het gebruik van onveranderlijke datastructuren kan helpen onze implementatie eenvoudiger te redeneren.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow