Scala Language
抽出器
サーチ…
構文
- val抽出子(抽出された値1、_ / *無視された第2の抽出値* /)= valueToBeExtracted
- valueToBeExtracted match {case extractor(extractedValue1、_)=> ???}
- val(tuple1、tuple2、tuple3)= tupleWith3Elements
- オブジェクトFoo {def unapply(foo:Foo):オプション[String] = Some(foo.x); }
タプルエクストラクタ
x
とy
はタプルから抽出されます:
val (x, y) = (1337, 42) // x: Int = 1337 // y: Int = 42
値を無視するには、 _
:を使用します。
val (_, y: Int) = (1337, 42) // y: Int = 42
エクストラクタを解凍するには:
val myTuple = (1337, 42) myTuple._1 // res0: Int = 1337 myTuple._2 // res1: Int = 42
タプルは22の最大長さを有することに留意されたいので、 ._1
スルー._22
動作する(タプルを仮定すると、少なくともそのサイズです)。
タプル抽出子は、リテラル関数のシンボリック引数を提供するために使用できます:
val persons = List("A." -> "Lovelace", "G." -> "Hopper") val names = List("Lovelace, A.", "Hopper, G.") assert { names == (persons map { name => s"${name._2}, ${name._1}" }) } assert { names == (persons map { case (given, surname) => s"$surname, $given" }) }
ケースクラスエクストラクタ
ケースクラスは、標準のボイラープレートコードが自動的に含まれるクラスです。これのメリットの1つは、Scalaではケースクラスで抽出機能を使いやすくすることです。
case class Person(name: String, age: Int) // Define the case class
val p = Person("Paola", 42) // Instantiate a value with the case class type
val Person(n, a) = p // Extract values n and a
// n: String = Paola
// a: Int = 42
この時点で、両方n
及びa
であるval
プログラム中のSをそのようにアクセスすることができる:それらは、Pから「抽出」されていると言われています。続ける:
val p2 = Person("Angela", 1337)
val List(Person(n1, a1), Person(_, a2)) = List(p, p2)
// n1: String = Paola
// a1: Int = 42
// a2: Int = 1337
ここでは2つの重要なことが分かります:
- 抽出は「深い」レベルで行うことができます。入れ子にされたオブジェクトのプロパティを抽出できます。
- すべての要素を抽出する必要はありません。ワイルドカード
_
文字は、その特定の値が何でもよいことを示し、無視されます。val
は作成されません。
特に、コレクションのマッチングを簡単にすることができます。
val ls = List(p1, p2, p3) // List of Person objects
ls.map(person => person match {
case Person(n, a) => println("%s is %d years old".format(n, a))
})
ここでは、明示的にチェックするために抽出器を使用するコード持っているperson
いるPerson
:オブジェクトとすぐに私たちが気に変数を引き出しn
と。 a
適用解除 - カスタム抽出
unapply
メソッドを実装し、 Option
型の値を返すことで、カスタム抽出を記述することができます。
class Foo(val x: String)
object Foo {
def unapply(foo: Foo): Option[String] = Some(foo.x)
}
new Foo("42") match {
case Foo(x) => x
}
// "42"
返される型unapply
は、返される型がget
およびisEmpty
メソッドを提供する場合、 Option
以外のものである可能性があります。この例では、 Bar
はこれらのメソッドで定義され、 unapply
はBar
インスタンスを返します。
class Bar(val x: String) {
def get = x
def isEmpty = false
}
object Bar {
def unapply(bar: Bar): Bar = bar
}
new Bar("1337") match {
case Bar(x) => x
}
// "1337"
unapply
の戻り値の型は、上記のget
およびisEmpty
要件を満たさない特殊なケースでもあるBoolean
にすることもできます。ただし、この例では、 DivisibleByTwo
はクラスではなくオブジェクトであり、パラメータを取らない(したがって、そのパラメータはバインドできません)。
object DivisibleByTwo {
def unapply(num: Int): Boolean = num % 2 == 0
}
4 match {
case DivisibleByTwo() => "yes"
case _ => "no"
}
// yes
3 match {
case DivisibleByTwo() => "yes"
case _ => "no"
}
// no
unapply
は、クラスではなく、クラスのコンパニオンオブジェクトにunapply
れることにunapply
ください。上記の例は、この区別を理解すれば明確になります。
エクストラクタの挿入表記法
ケースクラスにちょうど2つの値がある場合、そのエクストラクタはインミックス表記で使用できます。
case class Pair(a: String, b: String)
val p: Pair = Pair("hello", "world")
val x Pair y = p
//x: String = hello
//y: String = world
2タプルを返す抽出器はこのように動作します。
object Foo {
def unapply(s: String): Option[(Int, Int)] = Some((s.length, 5))
}
val a Foo b = "hello world!"
//a: Int = 12
//b: Int = 5
正規表現抽出プログラム
グループ化された部分を持つ正規表現を抽出子として使用できます。
scala> val address = """(.+):(\d+)""".r
address: scala.util.matching.Regex = (.+):(\d+)
scala> val address(host, port) = "some.domain.org:8080"
host: String = some.domain.org
port: String = 8080
一致していない場合、実行時にMatchError
がスローされることに注意してください。
scala> val address(host, port) = "something not a host and port"
scala.MatchError: something not a host and port (of class java.lang.String)
変換可能抽出
エクストラクタの振る舞いは、入力から任意の値を導出するために使用できます。これは、変換が成功した場合に変換の結果を処理できるようにする場合に役立ちます。
たとえば、 Windows環境で使用できるさまざまなユーザー名形式を例として考えてみましょう。
object UserPrincipalName {
def unapply(str: String): Option[(String, String)] = str.split('@') match {
case Array(u, d) if u.length > 0 && d.length > 0 => Some((u, d))
case _ => None
}
}
object DownLevelLogonName {
def unapply(str: String): Option[(String, String)] = str.split('\\') match {
case Array(d, u) if u.length > 0 && d.length > 0 => Some((d, u))
case _ => None
}
}
def getDomain(str: String): Option[String] = str match {
case UserPrincipalName(_, domain) => Some(domain)
case DownLevelLogonName(domain, _) => Some(domain)
case _ => None
}
実際には一致させることができるタイプを広げることによって、両方の動作を示すエクストラクタを作成することが可能です:
object UserPrincipalName {
def unapply(obj: Any): Option[(String, String)] = obj match {
case upn: UserPrincipalName => Some((upn.username, upn.domain))
case str: String => str.split('@') match {
case Array(u, d) if u.length > 0 && d.length > 0 => Some((u, d))
case _ => None
}
case _ => None
}
}
一般に、抽出子は、 tryParse
ような名前のメソッドに適用されるOption
パターンの便利な再構成です。
UserPrincipalName.unapply("user@domain") match {
case Some((u, d)) => ???
case None => ???
}