Сопоставление с образцом
Экстракторы
Экстракторы — это объекты, которые предоставляют метод unapply
или unapplySeq
:
def unapply[A](x: T)(implicit x: B): U
def unapplySeq[A](x: T)(implicit x: B): U
Экстракторы, предоставляющие метод unapply
, называются экстракторами с фиксированной арностью.
Экстракторы, предоставляющие метод unapplySeq
, называются экстракторами с переменным числом параметров.
Экстракторы с фиксированной арностью
Экстракторы с фиксированной арностью предоставляют следующую подпись:
def unapply[A](x: T)(implicit x: B): U
Тип U
соответствует одному из следующих совпадений:
- Логическое совпадение
- Соответствие продукта
Или U
соответствует типу R
:
type R = {
def isEmpty: Boolean
def get: S
}
и S
соответствует одному из следующих совпадений:
- одно совпадение
- совпадение по имени
Первая форма unapply
имеет более высокий приоритет,
а одиночное совпадение имеет более высокий приоритет, чем сопоставление на основе имени.
Использование экстрактора с фиксированной арностью применяется, если выполняется одно из следующих условий:
U = true
- экстрактор используется в качестве соответствия продукта
U = Some[T]
(для совместимости со Scala 2)U <: R
, а такжеU <: { def isEmpty: false }
Логическое совпадение
Пример:
object Even:
def unapply(s: String): Boolean = s.size % 2 == 0
"even" match
case s @ Even() => println(s"$s has an even number of characters")
case s => println(s"$s has an odd number of characters")
// even has an even number of characters
Соответствие продукта
Пример:
class FirstChars(s: String) extends Product:
def _1 = s.charAt(0)
def _2 = s.charAt(1)
// Not used by pattern matching: Product is only used as a marker trait.
def canEqual(that: Any): Boolean = ???
def productArity: Int = ???
def productElement(n: Int): Any = ???
object FirstChars:
def unapply(s: String): FirstChars = new FirstChars(s)
"Hi!" match
case FirstChars(char1, char2) =>
println(s"First: $char1; Second: $char2")
// First: H; Second: i
Одиночное совпадение
Пример:
class Nat(val x: Int):
def get: Int = x
def isEmpty = x < 0
object Nat:
def unapply(x: Int): Nat = new Nat(x)
5 match
case Nat(n) => println(s"$n is a natural number")
case _ => ()
// 5 is a natural number
Совпадение по имени
Пример:
object ProdEmpty:
def _1: Int = ???
def _2: String = ???
def isEmpty = true
def unapply(s: String): this.type = this
def get = this
"" match
case ProdEmpty(_, _) => ???
case _ => println("not ProdEmpty")
// not ProdEmpty
Экстракторы с переменным числом параметров
Экстракторы с переменным числом параметров предоставляют следующую сигнатуру:
def unapplySeq[A](x: T)(implicit x: B): U
Тип U
соответствует одному из следующих совпадений:
- соответствие последовательности
- соответствие последовательности продуктов
Или U
соответствует типу R
:
type R = {
def isEmpty: Boolean
def get: S
}
и S
соответствует одному из двух совпадений выше.
Соответствие последовательности имеет более высокий приоритет, чем соответствие последовательности продуктов.
Использование экстрактора с переменным числом параметров применяется, если выполняется одно из следующих условий:
- экстрактор используется непосредственно как соответствие последовательности или соответствие продукта последовательности
U = Some[T]
(для совместимости со Scala 2)U <: R
, а такжеU <: { def isEmpty: false }
Совпадение последовательности
Пример:
object CharList:
def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList)
"example" match
case CharList(c1, c2, c3, c4, _, _, _) =>
println(s"$c1,$c2,$c3,$c4")
case _ =>
println("Expected *exactly* 7 characters!")
// e,x,a,m
Соответствие последовательности продуктов
Пример:
class Foo(val name: String, val children: Int*)
object Foo:
def unapplySeq(f: Foo): Option[(String, Seq[Int])] =
Some((f.name, f.children))
def foo(f: Foo): Unit = f match
case Foo(name, x, y, ns*) =>
println(s"name = $name, x = $x, y = $y, ns = $ns")
case Foo(name, ns*) =>
println(s"name = $name, ns = $ns")
foo(new Foo("first", 2))
// name = first, ns = ArraySeq(2)
foo(new Foo("first", 2, 3))
// name = first, x = 2, y = 3, ns = ArraySeq()
foo(new Foo("first", 2, 3, 4))
// name = first, x = 2, y = 3, ns = ArraySeq(4)
Ссылки: