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 |