Scala のオプションを理解する
この記事では、Scala でオプションのデータ要素を操作する方法を学びます。Scala の Option は、堅牢なコードを書くのに役立ちます。
Scala の Option 型
Scala の Option[T] は、指定されたタイプの 0 個または 1 個の値を格納する container です。Scala の Option を使用してオプションの値を管理することで、次の 2つのことを保証できます。
- タイプセーフティ:オプションの値をパラメータ化できます。
- 機能認識:
Optionタイプは、プログラムで作成されるバグを少なくするための多くの機能機能を提供します。
Scala では、Option[T] は Some[T] または None[T] オブジェクトのいずれかで表されます。ここで、scala.Option は抽象的で拡張された基本クラスであり、Scala の Option をコンテナーのように動作させます。
Option クラスとそのサブクラスには具象型が必要であることに注意してください。これらは、明示的にすることも、次の構文のように推測することもできます。
例:
val obj1: Option[Int] = None
val obj2 = Some(100)
ここで、obj1 と obj2 は Option[Int] のオブジェクトです。よくある質問の 1つは、Option が一部かなしかを確認する方法です。
この問題を解決するために、以下の機能があります。
isEmpty:オブジェクトがNoneの場合、このメソッドはtrueを返します。nonEmpty:オブジェクトがSomeの場合、このメソッドはtrueを返します。isDefined:オブジェクトがSomeの場合、このメソッドはtrueを返します。
Scala で Option の値を取得する
get メソッドを使用して、Options 値を取得できます。get メソッドが None のオブジェクトで呼び出されると、NoSuchElementException がスローされます。これは成功バイアスとも呼ばれます。
サンプルコード:
val obj1: Option[Int]= ...
val v1 = if (obj1.isDefined)
{
obj1.get
}
else
{
0
}
上記のコードは、パターンマッチングを使用して記述することもできます。
サンプルコード:
val obj1: Option[Int]= ...
val v1 = obj1 match {
case Some(temp) =>
temp
case None =>
0
}
値を取得するための getOrElse や orElse などの他のメソッドもあります。
getOrElse:このメソッドは、オブジェクトがSomeの場合に値を取得します。それ以外の場合は、デフォルト値を返します。orElse:このメソッドは、オブジェクトがSomeの場合に値を取得します。それ以外の場合は、alternateオプションを返します。
オプションの値が設定されていない場合、デフォルト値を返すことができるため、getOrElse メソッドは非常に便利です。
構文:
val v1 = obj1.getOrElse(0)
Scala のコンテナとしての Option
Scala では、Option が別の値を格納するコンテナであることを見てきました。ちょうど List をトラバースするように、Option をトラバースすることができます。
このコンテナのいくつかのメソッドを見てみましょう。Scala の Option.map メソッドの構文:
final def map[Y](f: (X) => Y): Option[Y]
サンプルコード:
val obj1: Option[Int] = Some(100)
assert(obj1.map(_.toString).contains("100"))
assert(obj1.map(_ * 2.0).contains(200))
val obj2: Option[Int] = None
assert(obj2.map(_.toString).isEmpty)
上記の例では、Option.map メソッドを使用して、含まれている値を別のタイプに変換しました。Option.map メソッドを使用して、プログラムのフロー制御に影響を与えることもできます。
サンプルコード:
val obj1: Option[Int] = Some(10)
val obj2: Option[Int] = None
def mul(n: Int): Int = n * 2
assert(obj1.map(mul).contains(20))
assert(obj2.map(mul).isEmpty)
ここでは、Option[Int] の 2つのオブジェクトを作成しました。最初のオブジェクトの値は 10 で、2 番目のオブジェクトは空です。次に、入力に 2 を掛けるメソッド mul を定義しました。
最後に、mul メソッドを使用して obj1 と obj2 をマップします。obj1 をマッピングすると Some(20) が得られ、obj2 をマッピングすると None が得られます。
ここで注意すべきことの 1つは、2 番目の呼び出し obj2.map(mul) では、mul メソッドがまったく呼び出されないことです。フィルタリングによるフロー制御も可能です。
これを行うには多くの方法があります。
filter:このメソッドは、Options値がSomeであり、提供された関数がtrueを返す場合、Optionを返します。exists:Optionが設定され、提供された関数がtrueを返す場合、このメソッドはtrueを返します。forall:existsメソッドと同じように動作します。
これらの関数を使用すると、コードを非常に簡潔に記述できます。
最高得点のチームを見つける例を見てみましょう。
サンプルコード:
def highScoringTeam(playerA: Player, playerB: Player, tournament: Tournament): Option[(Player, Int)] =
{ getTopScore(playerA, tournament).foldRight(getTopScore(playerB, tournament)) {
case (playerAInfo, playerBInfo) => playerBInfo.filter {
case (_, scoreB) => scoreB > playerAInfo._2
}.orElse(Some(playerAInfo))
}
}
上記のコードでは、Option をコレクションとして使用できることを利用しています。唯一の違いは、オプションは最大で 1つの値を持つことができるということです。
