Как пропускается слово соответствия в Scala?
В Scala вы можете сделать
list.filter { item =>
item match {
case Some(foo) => foo.bar > 0
}
}
Но вы также можете сделать более быстрый путь, опуская match
:
list.filter {
case Some(foo) => foo.bar > 0
}
Как это поддерживается в Scala? Это новое в 2.9? Я искал это, и я могу выяснить, что делает это возможным. Это просто часть компилятора Scala?
3 ответа
Спецификация языка обращается к этому в разделе 8.5. Соответствующие части:
Анонимная функция может быть определена последовательностью случаев
{ case p1 => b1 ... case pn => bn }
Если ожидаемый тип
scala.Functionk[S1, ..., Sk, R]
, выражение считается эквивалентным анонимной функции:
(x1 : S1, ..., xk : Sk) => (x1, ..., xk) match {
case p1 => b1 ... case pn => bn
}
Если ожидаемый тип
scala.PartialFunction[S, R]
, выражение считается эквивалентным следующему выражению создания экземпляра:
new scala.PartialFunction[S, T ] {
def apply(x: S): T = x match {
case p1 => b1 ... case pn => bn
}
def isDefinedAt(x: S): Boolean = {
case p1 => true ... case pn => true
case _ => false
}
}
Таким образом, набрав выражение как PartialFunction
или Function
влияет на то, как компилируется выражение.
Также trait PartialFunction [-A, +B] extends (A) ⇒ B
так частичная функция PartialFunction[A,B]
также Function[A,B]
,
Изменить: части этого ответа неверны; пожалуйста, обратитесь к ответу Huynhjl.
Если вы опустите match
Вы сообщаете компилятору, что определяете частичную функцию. Частичная функция - это функция, которая не определена для каждого входного значения. Например, ваша функция фильтра определяется только для значений типа Some[A]
(для вашего пользовательского типа A
).
PartialFunction
скинуть MatchError
когда вы пытаетесь применить их там, где они не определены. Таким образом, вы должны убедиться, когда вы передаете PartialFunction
где обычный Function
определено, что ваша частичная функция никогда не будет вызываться с произвольным аргументом. Такой механизм очень полезен, например, для распаковки кортежей в коллекции:
val tupleSeq: Seq[(Int, Int)] = // ...
val sums = tupleSeq.map { case (i1, i2) => i1 + i2 }
API, которые запрашивают частичную функцию, такую как collect
Фильтрующая операция над коллекциями, обычно isDefinedAt
перед применением частичной функции. Там безопасно (и часто требуется) иметь частичную функцию, которая не определена для каждого входного значения.
Итак, вы видите, что хотя синтаксис близок к синтаксису match
на самом деле это совсем другое дело, с которым мы имеем дело.
- Пересмотренный пост -
Хм, я не уверен, что вижу разницу, Scala 2.9.1.RC3,
val f: PartialFunction[Int, Int] = { case 2 => 3 }
f.isDefinedAt(1) // evaluates to false
f.isDefinedAt(2) // evaluates to true
f(1) // match error
val g: PartialFunction[Int, Int] = x => x match { case 2 => 3 }
g.isDefinedAt(1) // evaluates to false
g.isDefinedAt(2) // evaluates to true
g(1) // match error
Похоже на то f
а также g
вести себя точно так же, как PartialFunctions
,
Вот еще один пример, демонстрирующий эквивалентность:
Seq(1, "a").collect(x => x match { case s: String => s }) // evaluates to Seq(a)
Еще интереснее
// this compiles
val g: PartialFunction[Int, Int] = (x: Int) => {x match { case 2 => 3 }}
// this fails; found Function[Int, Int], required PartialFunction[Int, Int]
val g: PartialFunction[Int, Int] = (x: Int) => {(); x match { case 2 => 3 }}
Так что на уровне компилятора есть специальный корпус для преобразования между x => x match {...}
и просто {...}
,
Обновление После прочтения спецификации языка это кажется мне ошибкой. Я подал SI-4940 в трекер ошибок.