Сопоставление шаблонов в Scala для String и Int

#scala #pattern-matching

#scala #сопоставление с образцом

Вопрос:

Почему сопоставление шаблонов в Scala работает для String и AnyVal s, таких как Int ?

Обычно мы видим такие вещи, как Case classes или Extractors

Ответ №1:

Экстракторы и классы case используются только для двух из 13 типов шаблонов в Scala, «Шаблонов извлечения» и «шаблонов конструктора» соответственно. Вы не можете использовать Int or String в этом типе pattern ( case String(x) ) . Но вы можете использовать их в других видах:

  1. Типизированные шаблоны, как в case x: String . В этом случае нет ничего особенного String , вы можете сделать то же самое с любым классом (но есть кое-что особенное в отношении Int и других примитивов: case x: Int фактически проверяет, является ли полученный объект a java.lang.Integer в большинстве случаев).

  2. Литеральные шаблоны, как в case 0 or case "" . Опять же, ничего особенного в строках, это работает для всех литералов.

Ответ №2:

java.lang.String обогащено scala.collection.immutable.StringOps (http://www.scala-lang.org/api/2.11.8/#scala.collection.immutable .StringOps), которые смешивают scala.collection.immutable.StringLike (http://www.scala-lang.org/api/2.11.8/#scala.collection.immutable .StringLike) в. Там вы можете найти дополнительные методы, такие как apply .

String также немного особенное, вы можете преобразовать его в list of Char s и List затем использовать экстракторы, подобные case List(a,b) or case x:xs на a String , имея в виду, что a and b будет Char s; x: Char и xs: List[Char]

Все примитивные типы имеют расширенные * классы (например scala.runtime.RichBoolean , scala.runtime.RichByte ).

Механика классов значений используется для обогащения всех вышеупомянутых типов (http://docs.scala-lang.org/overviews/core/value-classes.html ). Во время компиляции они имеют тип оболочки, например RichBoolean or RichInt , но во время выполнения они являются чисто логическими или Int типами. Таким образом, избегая накладных расходов на создание объектов среды выполнения.

Комментарии:

1. «Строка также немного особенная, поскольку это всего лишь список символов, что означает, что вы можете использовать экстракторы списков, такие как case List(a, b) или case x: xs для строки» Попробуйте.

2. @AlexeyRomanov вы правы, вам нужно сделать toList , прежде чем это сработает. Я, честно говоря, думал, что это сработает без дополнительных усилий%). Я отредактирую answear.

3. Даже тогда преобразование строки в a List[Char] происходит довольно медленно, и результирующий список занимает намного больше памяти, чем String . Гораздо лучше использовать toSeq (или неявное преобразование в Seq[Char] ), которое просто создаст небольшой объект-оболочку и будет использовать Seq специфические (но не List специфические) методы и средства сопоставления.

Ответ №3:

 val x: Any = 5
def f[T](v: T) = v match {
  case _: Int    => "Int"
  case _: String => "String"
  case _         => "Unknown"
}
  

Комментарии:

1. Я спрашиваю, почему это работает. String — это псевдоним для java.lang. String, это ни класс case, ни экстрактор, поправьте меня, если я ошибаюсь.

Ответ №4:

Вам не нужно определять unapply в классе, чтобы иметь возможность использовать этот класс в switch/case стиле сопоставления с образцом. unapply используется для деконструкции объекта, поэтому, если вы хотите сопоставить switch in List -style ( case x:xs ) , вам следует использовать unapply/unapplySeq . Хорошим примером здесь являются регулярные выражения, они построены из строк — "something".r (примечание .r в конце).