S-JIS[2011-01-09/2011-06-18] 変更履歴

Scala Option(Some・None)

ScalaのOptionは、値をラップする(包む)クラス。


概要

何かの処理結果(オブジェクト)を返すメソッドにおいて、処理できなかった時にJavaではnullを返すようにする事がある。
しかしnullだと、そのまま使うとNullPointerExceptionになってしまう。

Scalaでは、そういう時にOptionクラスを使う。
Optionクラスの子クラスにはSomeクラスNoneオブジェクトがある。
返したい値はSomeに入れて返す。
処理できなかった事を表すときはNoneを返す。

scala> def div(n: Int, m: Int) = {
     |   if (m != 0) Some(n / m) else None
     | }
div: (n: Int,m: Int)Option[Int]

scala> div(10, 5)
res1: Option[Int] = Some(2)

scala> div(1, 0)
res2: Option[Int] = None

Optionのメソッド

Option(Some・None)のメソッド。

メソッド(例) 処理結果 備考
Someのとき Noneのとき
opt.isEmpty
false true  
opt.isDefined
opt.nonEmpty
true false  
opt.get
入っている値 NoSuchElementExceptionが発生  
opt.getOrElse(デフォルト値)
入っている値 指定されたデフォルト値 戻り値の型は、入っている値とデフォルト値の共通の親クラスになる。
opt.orNull
入っている値 null AnyVal(Int等)が入っているSomeでは使えない。 (コンパイルエラー)
opt.orElse(Option(値))
自分自身 指定されたOption(値)  
opt match {
  case Some(v) => v
  case _ => "nothing"
}
入っている値 "nothing"  
Option(値)
Option.apply(値)
  値がnull以外だとSome(値)を返す。
値がnullだとNoneを返す。(Scala2.8以降の仕様らしい。[2011-06-12]
(nullを返すようなJavaのメソッドの戻り値をOptionにしたい場合に便利)
Some(値)
Some.apply(値)
  Some(値)を返す。
値がnullだったら、nullを保持したSomeが返る。
Some(値1,値2)と書くと、(値1,値2)というタプルが値になる。
これは、Some.apply(値1,値2)という呼び出しであり
Someのapply()は引数が1個のメソッドである。
Scalaでは引数が1個のときは丸括弧が省略できるので
Some.apply 値」と解釈され、値部分がタプルと見なされる。

その他にforeach・filter・mapといったメソッドコレクションと同様)がある。
基本的にSomeの場合だけ処理される。Noneだと無処理。Listで例えれば、Noneは空リスト(Nil)だから。


応用例

Optionを使ったコーディング例。[2011-05-04]

やりたい事 単純な考え方 良さそうな方法 備考
値が有るときだけ処理する。
[2011-04-10]
opt match {
  case Some(v) => println(v)
  case _ =>
}
opt.foreach { v =>
  println(v)
}
foreachを使うと、値が有るとき(Someのとき)だけ実行される。
 
値が有るときは変換し、無いときはデフォルト値を返す。
[2011-05-04]
val r = opt match {
  case Some(v) => v.convert
  case _ => デフォルト値
}
val r = opt.map(_.convert).
  getOrElse(デフォルト値)
Noneのmapは(何もせず)常にNoneを返すので
最後のgetOrElseでデフォルト値が返る。
Listが空でないときは先頭要素、空のときはデフォルト値を返す。
[2011-06-18]
val r = if (list.nonEmpty) list.head
  else デフォルト値
val r = list.headOption.
  getOrElse(デフォルト値)
headOptionは、値があればそれをSomeに入れて返す。無ければNoneを返す。
null以外のときだけメソッドを呼び出し、それ以外のときはnullを返す。
[2011-06-04]
if (v ne null) v.convert else null
Option(v).map(_.convert).orNull
 
ある条件を満たすならその値、それ以外はデフォルト値を返す。
[2011-06-12]
if (v >= 0) v else -1
Some(v).filter(_ >= 0).
  getOrElse(-1)
参考: missingfaktorさんのツイート
vがAnyVal(Intとか)ならnullになることは無いので、OptionでなくSomeでいい。
null以外のときだけ条件判断を行う。
[2011-04-24]
if ((v ne null) &&
    (vを使った条件判断)) {
  〜
}
if (Option(v).exists{ v =>
  vを使った条件判断
}) {
  〜
}
vがnullだとOption(v)はNoneになるので、existsは(何もせず)常にfalseとなる。
メソッドの戻り値がnull以外の間、処理を実行する。
[2011-06-04]
val br = new BufferedReader(〜)
var s = ""
while ({ s = br.readLine; s ne null}) {
  println(s)
}
val br = new BufferedReader(〜)
new Iterator[String] {
  var opt = Option(br.readLine)
  def hasNext = opt.nonEmpty
  def next() = {
    val r = opt.orNull
    opt = Option(br.readLine)
    r
  }
}.foreach { s =>
  println(s)
}
ScalaでReaderを扱う例
値のあるオプションだけSeqに入れる。
[2011-05-04]
var seq = Seq.empty[A]
if (opt1.nonEmpty) {
  seq :+= opt1.get
}
if (opt2.nonEmpty) {
  seq :+= opt2.get
}
var seq = Seq.empty[A]
seq ++= opt1
seq ++= opt2
seq :+= v」は「seq = seq :+ v」と同じ
:+」は要素を末尾に追加する演算子。
++」はコレクション同士を結合する演算子。
Optionもコレクション扱いとなる。
val seq = opt1.toSeq ++
  opt2
val seq = (opt1 ++ opt2).toSeq

Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま