問題
Option型の変数に対して中身があるとき(= Someであるとき)のみ特定の処理をしたい場合どう書きますか?
val nameOption: Option[String] = Some("bob")
// nameOptionの中身があるならそれをprintlnしたい
解法
for文または foreach
メソッドを使いましょう。
for (name <- nameOption) // for文のパターン
println(name)
nameOption.foreach { name => println(name) } // foreachメソッドのパターン
nameOption.foreach(println) // 省略してこう書いてもOK
解説
問題で書いた処理を実現したいとき、Scalaビギナーが以下のようなコードが書くのをよく目にします。
if (nameOption.nonEmpty)
println(nameOption.get)
nameOption match {
case Some(name) => println(name)
case None => ()
}
しかし、これらのコードはどちらも問題があります。
前者は危険な可能性のあるgetを使っており1、後者は何も処理をしないNoneのケースをわざわざ書いてやる必要があります。
実際には件の処理は foreach メソッドとしてデフォルトで実装されています。
scala/Option.scala at v2.13.1 · scala/scala
/** Apply the given procedure $f to the option's value,
* if it is nonempty. Otherwise, do nothing.
*
* This is equivalent to:
* {{{
* option match {
* case Some(x) => f(x)
* case None => ()
* }
* }}}
* @param f the procedure to apply.
* @see map
* @see flatMap
*/
@inline final def foreach[U](f: A => U): Unit = {
if (!isEmpty) f(this.get)
}
備考
Scalaのfor文は単に foreach
メソッドの糖衣構文であるため foreach
メソッドが定義されていれば foreach
メソッド呼び出しと同様に使用できます。
6.19 For Comprehensions and For Loops | Expressions | Scala 2.13
参考
- Scala Standard Library 2.12.8 - scala.Option
- Option型がSomeであるときのみ特定の処理をするときのメソッド名が foreach なのか - Qiita
-
getは変数がNoneの場合例外が発生します。もちろん上のコードではその直前でNoneでないことをチェックしていますが、チェックしてから実際に使用するまでの間にコードが挟まったり並列実行などで元の変数が書き換えられる可能性を考えると例外が発生する可能性は否めません ↩