Reputation: 17104
As a Java-to-Scala switcher, I routinely find myself rewriting null handling stuff like
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)
}
}
I guess it looks ugly and it really looks like a piece of code rewritten from Java's:
Item item = items.get(coords);
if (item != null) {
// do something with item, querying item fields a lot of times, for example
}
It also looks ugly in Java, but at least it's one line less. What is the best practice to handle such simple cases in Scala? I already know of flatMap
and flatten
to handle collections of Option[Stuff]
, and I know of getOrElse
to handle default values. I dream of something like:
items.get(coords).doIfDefined(item =>
// do stuff with item
)
but I don't see anything like that in Option
API.
Upvotes: 9
Views: 1528
Reputation: 26566
Very popular usage pattern:
val item: Option[Int] = None
val result = item map (_ + 1) getOrElse 0
so you just use map
in order to transform value if it's defined.
If you just want to use value, that is stored within an Option
, then just use foreach
:
item foreach { it =>
println(it)
}
As you can see, Option
also supports many collection methods, so you actually don't need to learn new API. You can just treat it as a collection with either 1 or 0 elements.
Upvotes: 12
Reputation: 8821
Also, Option could be used in Pattern Matching with if
guard. personally I like use it in this scenario, and think it is easier to read.
Because map
on a Option will only has effect when you Option is not None
, so you could do it first, and then using Pattern Matching to inspect to see if your itemOpt is a Some
or 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 =>
}
Upvotes: 3
Reputation: 6920
Check this Tony Morris post. It helped me very much when I tried to understand Option. Your code may be rewritten in such way:
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)
}
}
Upvotes: 5
Reputation: 7848
This should accomplish what you are looking to do:
items.get(coords).foreach{ item =>
//do stuff
}
Upvotes: 7