#scala #pattern-matching
#scala #сопоставление с образцом
Вопрос:
Почему сопоставление шаблонов в Scala работает для String
и AnyVal
s, таких как Int
?
Обычно мы видим такие вещи, как Case classes
или Extractors
…
Ответ №1:
Экстракторы и классы case используются только для двух из 13 типов шаблонов в Scala, «Шаблонов извлечения» и «шаблонов конструктора» соответственно. Вы не можете использовать Int
or String
в этом типе pattern ( case String(x)
) . Но вы можете использовать их в других видах:
-
Типизированные шаблоны, как в
case x: String
. В этом случае нет ничего особенногоString
, вы можете сделать то же самое с любым классом (но есть кое-что особенное в отношенииInt
и других примитивов:case x: Int
фактически проверяет, является ли полученный объект ajava.lang.Integer
в большинстве случаев). -
Литеральные шаблоны, как в
case 0
orcase ""
. Опять же, ничего особенного в строках, это работает для всех литералов.
Ответ №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
в конце).