2012-12-18 20 views
9

Come un Java-to-Scala switcher, Io abitualmente ritrovo riscrittura roba movimentazione nulla comeScala migliori pratiche: semplice opzione di utilizzo []

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) 
    } 
} 

Credo che sembra brutto e davvero si presenta come un pezzo di codice riscritto da Java di:

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

sembra anche brutto in Java, ma almeno è una linea meno. Qual è la migliore pratica per gestire casi così semplici in Scala? Conosco già lo flatMap e lo flatten per gestire le raccolte di Option[Stuff] e so di getOrElse per gestire i valori predefiniti. Io sogno di qualcosa di simile:

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

ma non vedo niente di simile in Option API.

+4

Questo potrebbe aiutare: http://dibblego.wordpress.com/2008/01/16/scalaoption-cheat-sheet/ – dhg

risposta

12

Molto popolare modello di utilizzo:

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

quindi basta usare map al fine di trasformare il valore se è definito.

Se si desidera utilizzare il valore, che viene memorizzato all'interno di un Option, poi basta usare foreach:

item foreach { it => 
    println(it) 
} 

Come si può vedere, Option supporta anche molti metodi di raccolta, in modo che in realtà non è necessario per imparare nuove API. Puoi trattarlo come una raccolta con 1 o 0 elementi.

7

Questo dovrebbe compiere ciò che si sta cercando di fare:

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

In alternativa, basta usare espressioni for 'per (voce <- maybeItem) {.. .} 'dove' maybeItem' è la tua opzione. –

+0

Per essere ancora più frugali, nota: 'items.get (coordina) mappa {item => // ...' –

5

Controllare questo Tony Morris post. Mi ha aiutato moltissimo quando ho cercato di capire l'opzione. Il tuo codice può essere riscritto in modo tale:

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

Inoltre, l'opzione potrebbe essere utilizzato in Pattern Matching con if guardia. personalmente mi piace usarlo in questo scenario, e penso che sia più facile da leggere.

Perché map su un'opzione solo si ha effetto quando opzione non è None, in modo che si possa fare per primo, e quindi utilizzando Pattern Matching per ispezionare per vedere se l'itemOpt è un Some o 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 => 
}