Szukaj…


Uwagi

Wartości i nazwy zmiennych powinny być pisane małymi literami wielbłąda

Nazwy stałe powinny być pisane wielkimi literami wielbłąda. Oznacza to, że jeśli element jest ostateczny, niezmienny i należy do obiektu pakietu lub obiektu, można go uznać za stały

Nazwy metod, wartości i zmiennych powinny być pisane małymi literami wielbłąda

Źródło: http://docs.scala-lang.org/style/naming-conventions.html

Ta kompilacja:

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

ale to nie:

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

To nie tylko val vs. var

val i 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
  • referencje val są niezmienne: jak final zmienna w Java , po jej zainicjowaniu nie można jej zmienić
  • var referencje są ponownie przypisać jako deklaracja zmiennej prosty w Javie

Kolekcje niezmienne i zmienne

  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)

Standardowa biblioteka Scala oferuje zarówno niezmienne, jak i zmienne struktury danych, a nie ich odniesienia. Za każdym razem, gdy niezmienna struktura danych zostaje „zmodyfikowana”, tworzona jest nowa instancja zamiast modyfikować oryginalny zbiór w miejscu. Każde wystąpienie kolekcji może mieć znaczącą strukturę z innym wystąpieniem.

Zmienna i niezmienna kolekcja (oficjalna dokumentacja Scala)

Ale w tym przypadku nie mogę użyć niezmienności!

Wybierzmy przykładowo funkcję, która pobiera 2 Map i zwraca Map zawierającą każdy element w ma i mb :

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

Pierwszą próbą może być iteracja elementów jednej z map za pomocą for ((k, v) <- map) i jakoś zwrócić scaloną mapę.

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

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

}

Ten pierwszy ruch natychmiast dodaje ograniczenie: potrzebna jest teraz mutacja poza tym for . Jest to wyraźniejsze, gdy odsłaniasz for :

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

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

„Dlaczego musimy mutować?”

foreach opiera się na skutkach ubocznych. Za każdym razem, gdy chcemy, aby coś się wydarzyło w obrębie foreach , musimy „coś var result efektem ubocznym”, w tym przypadku moglibyśmy zmutować zmienny var result lub możemy zastosować zmienną strukturę danych.

Tworzenie i wypełnianie mapy result

Załóżmy, że ma i mb to scala.collection.immutable.Map , możemy utworzyć result Map z ma :

val result = mutable.Map() ++ ma

Następnie iteruj przez mb dodając jego elementy i jeśli key bieżącego elementu na ma już istnieje, zastąpmy go mb .

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

Zmienna implementacja

Jak dotąd tak dobrze, „musieliśmy używać zmiennych zbiorów”, a poprawną implementacją może być:

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
}

Zgodnie z oczekiwaniami:

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

Składany na ratunek

Jak możemy pozbyć się foreach w tym scenariuszu? Jeśli wszystko, co należy zrobić, to w zasadzie iterować elementy kolekcji i zastosować funkcję, kumulując wynik opcji, można użyć .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) { _ + _ }
}

W tym przypadku naszym „wynikiem” jest skumulowana wartość zaczynająca się od ma , zero z .foldLeft .

Wynik pośredni

Oczywiście to niezmienne rozwiązanie powoduje i niszczy wiele instancji Map podczas składania, ale warto wspomnieć, że te instancje nie są pełnym klonem zgromadzonej Map ale zamiast tego dzielą znaczącą strukturę (dane) z istniejącą instancją.

Łatwiejsza racjonalność

Łatwiej jest wnioskować o semantyce, jeśli jest ona bardziej deklaratywna jak podejście .foldLeft . Korzystanie z niezmiennych struktur danych może pomóc w usprawnieniu naszej implementacji.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow