質問

Apologies if this is a newbie question... In Scala I understand that it is preferred to use an Option rather than returning null when you have a function which returns an instance but could potentially return nothing. I understand that this makes it better with regards to safety, because you are not passing null references around, and risking NullPointerException somewhere down the line.

However, is there a cleaner way to handle options than using pattern matching? The syntax I end up using is the following:

val optObj : Option[MyObject] = myFunctionThatReturnsOption
optObj match {
  case Some(obj) => {
  //my code using obj
  }

  case None => _
}

In reality all this doing is the equivalent of the Java version:

MyObject obj = myMethodThatCanReturnNull()
if (obj != null) {
  //my code using obj
}

Is there some other way to avoid all this boilerplate in Scala when using Option instead of null references? All I want to do is execute a piece of code as long as the Option contains some object (i.e. is not None).

役に立ちましたか?

解決

Use foreach, getOrElse and/or map if you want to work in a more consistent way. Here's some use cases and what I'd do:

 //I want to get a non-null value and I have a sane default
 val result = myOption getOrElse 3

 //I want to perform some side effecting action but only if not None
 myOption foreach{ value =>
   println(value toString ())
 }
 //equivalently
 for(value <- myOption){
   //notice I haven't used the "yeild" keyword here
 }

 //I want to do a computation and I don't mind if it comes back as an Option
 val result = for(value <- myOption) yield func(value)
 val equivalent = myOption map func

The third example will use map in both cases.

It gets really interesting when you can mix and match things in a "for comprehension" (Google term.) Let's say that func also returns an Option but I only want things working in specific cases:

 val result = for{ 
   value <- myOption if value > 0
   output <- func(value)
 } yield output

Now I get back an Option but only if myOption contained an integer that was greater than zero. Pretty nifty stuff, no?

他のヒント

You can use foreach if you just want to perform some side-effecting operation with the value:

optObj.foreach(obj => {
    //my code using obj
})

if you have some other use case you should use some other method on Option like map, filter or getOrElse.

Of course, the way I usually use options if I only care about present value is foreach:

optObj.foreach { obj => 
 //...
}

Having said this, there are a lot of other options (which @wheaties enlisted) and some people keep battling about the true one.

You can use the flatMap-method pretty well with Option. Like hier:

case class Player(name: String)
def lookupPlayer(id: Int): Option[Player] = {
  if (id == 1) Some(new Player("Sean"))
  else if(id == 2) Some(new Player("Greg"))
  else None
}
def lookupScore(player: Player): Option[Int] = {
  if (player.name == "Sean") Some(1000000) else None
}

println(lookupPlayer(1).map(lookupScore))  // Some(Some(1000000))
println(lookupPlayer(2).map(lookupScore))  // Some(None)
println(lookupPlayer(3).map(lookupScore))  // None

println(lookupPlayer(1).flatMap(lookupScore))  // Some(1000000)
println(lookupPlayer(2).flatMap(lookupScore))  // None
println(lookupPlayer(3).flatMap(lookupScore))  // None

Here's a great reference for Scala best practices regarding options: http://blog.tmorris.net/posts/scalaoption-cheat-sheet/index.html

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top