Это может помочь:
class Matches(m: Any) {
def matches[R](f: PartialFunction[Any, R]) { if (f.isDefinedAt(m)) f(m) }
}
implicit def any2matches(m: Any) = new Matches(m)
scala> 'c' matches { case x: Int => println("Int") }
scala> 2 matches { case x: Int => println("Int") }
Int
Теперь немного объяснения общего характера проблемы.
Где может происходить совпадение?
Существует три места, где может происходить сопоставление с образцом: val
, case
и for
.Правила для них:
// throws an exception if it fails
val pattern = value
// filters for pattern, but pattern cannot be "identifier: Type",
// though that can be replaced by "id1 @ (id2: Type)" for the same effect
for (pattern <- object providing map/flatMap/filter/withFilter/foreach) ...
// throws an exception if none of the cases match
value match { case ... => ... }
Однако существует другая ситуация, в которой может появиться case
- литералы функций и частичных функций.Например:
val f: Any => Unit = { case i: Int => println(i) }
val pf: PartialFunction[Any, Unit] = { case i: Int => println(i) }
Функции и частичные функции будут вызывать исключение, если их вызывать с аргументом, который не соответствует ни одному из операторов case.Тем не менее, частичные функции также предоставляют метод с именем isDefinedAt
, который может проверять, может ли быть найдено соответствие, а также метод с именем lift
, который превратит PartialFunction[T, R]
в Function[T, Option[R]]
, что означает не-согласование значений приведет к None
вместо выдачи исключения.
Что такое совпадение?
Совпадение - это комбинация множества различных тестов:
// assign anything to x
case x
// only accepts values of type X
case x: X
// only accepts values matches by pattern
case x @ pattern
// only accepts a value equal to the value X (upper case here makes a difference)
case X
// only accepts a value equal to the value of x
case `x`
// only accept a tuple of the same arity
case (x, y, ..., z)
// only accepts if extractor(value) returns true of Some(Seq()) (some empty sequence)
case extractor()
// only accepts if extractor(value) returns Some something
case extractor(x)
// only accepts if extractor(value) returns Some Seq or Tuple of the same arity
case extractor(x, y, ..., z)
// only accepts if extractor(value) returns Some Tuple2 or Some Seq with arity 2
case x extractor y
// accepts if any of the patterns is accepted (patterns may not contain assignable identifiers)
case x | y | ... | z
Теперь экстракторы - это методы unapply
или unapplySeq
, первый из которых возвращает Boolean
или Option[T]
, а второй возвращает Option[Seq[T]]
, где None
означает, что совпадение не выполнено, и Some(result)
попытаетсячтобы соответствовать result
, как описано выше.
Таким образом, здесь есть все виды синтаксических альтернатив, которые просто невозможны без использования одной из трех конструкций, где может происходить сопоставление с образцом.Вы можете эмулировать некоторые функции, такие как равенство значений и экстракторы, но не все из них.