S-JIS[2011-01-09/2017-01-16] 変更履歴
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(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.map(関数) |
Some(関数の処理結果) | None | Optionに入っている中身を変換する。[2017-01-16] 関数がnullを返してもNoneにはならない。 →コレクションのmap |
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 |