Как пропускается слово соответствия в 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 в трекер ошибок.

Другие вопросы по тегам