2012-12-18 11 views
9

Jako Java do Scala Switcher, ja rutynowo znaleźć się przepisywanie zerowej manipulacyjną rzeczy jakScala najlepsze praktyki: prosta opcja [] Użycie

val itemOpt: Option[Item] = items.get(coords) // "items" is something like a Map 
if (itemOpt.isDefined) { 
    val item = itemOpt.get 
    // do something with item, querying item fields a lot of times, for example 
    if (item.qty > 10) { 
    storeInVault(item.name, item.qty, coords) 
    } else { 
    storeInRoom(item) 
    } 
} 

myślę, że wygląda brzydko i naprawdę wygląda jak fragment kodu przepisany z Javy:

Item item = items.get(coords); 
if (item != null) { 
    // do something with item, querying item fields a lot of times, for example 
} 

Wygląda też paskudnie w Javie, ale przynajmniej jest o jedną linię mniej. Jaka jest najlepsza praktyka radzenia sobie z tak prostymi przypadkami w Scali? Już wiem o flatMap i flatten do obsługi kolekcji Option[Stuff] i znam getOrElse do obsługi wartości domyślnych. Marzę o czymś takim:

items.get(coords).doIfDefined(item => 
    // do stuff with item 
) 

ale nie widzę nic takiego w Option API.

+4

To może pomóc: http://dibblego.wordpress.com/2008/01/16/scalaoption-cheat-sheet/ – dhg

Odpowiedz

12

Bardzo popularny wzór wykorzystania:

val item: Option[Int] = None 
val result = item map (_ + 1) getOrElse 0 

tak po prostu użyć map w celu przekształcenia wartości, jeśli jest zdefiniowany.

Jeśli chcesz po prostu użyć wartości, które są przechowywane w ramach Option, następnie wystarczy użyć foreach:

item foreach { it => 
    println(it) 
} 

Jak widać, Option obsługuje również wiele metod gromadzenia, więc faktycznie nie potrzebują nauczyć się nowego API. Możesz po prostu traktować to jako kolekcję z 1 lub 0 elementami.

7

ten powinien osiągnąć to, czego szukasz zrobić:

items.get(coords).foreach{ item => 
    //do stuff 
} 
+6

Alternatywnie, wystarczy użyć do wyrażenia listowe 'dla (pozycja <- maybeItem) {.. .} 'where' maybeItem' jest twoją opcją. –

+0

Aby być jeszcze bardziej oszczędnym, uwaga: 'items.get (coords) map {item => // ... –

5

Sprawdź to Tony Morris post. Bardzo mi pomógł, gdy próbowałem zrozumieć Opcję. Kod może zostać przepisany w taki sposób:

for (item <- items.get(coords)) { // "items" is something like a Map 
    // do something with item, querying item fields a lot of times, for example 
    if (item.qty > 10) { 
    storeInVault(item.name, item.qty, coords) 
    } else { 
    storeInRoom(item) 
    } 
} 
3

Również Opcja może być używana w Pattern Matching z if straży. osobiście lubię go używać w tym scenariuszu i uważam, że jest łatwiejszy do odczytania.

Ponieważ map na opcja ma wpływ tylko wtedy, gdy opcja nie jest None, więc można zrobić, to po pierwsze, a następnie za pomocą wzorzec dopasowania do sprawdzenia, czy Twój itemOpt jest Some lub None.

def shouldInVault(item: Item) = item.qty > 10 

val itemOpt: Option[Item] = items.get(coords).map(...) 

itemOpt match { 
    case Some(item) if shouldInVault(item) => storeInVault(item.name, item.qty, coords) 
    case Some(item) => storeInRoom(item) 
    case None => 
}