Как пропускается слово соответствия в Scala? - PullRequest
12 голосов
/ 24 августа 2011

В 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 ]

18 голосов
/ 24 августа 2011

Редактировать : части этого ответа неверны;см. ответ huynhjl .


Если вы опустите match, вы сообщаете компилятору, что определяете частичную функцию .Частичная функция - это функция, которая не определена для каждого входного значения.Например, ваша функция фильтра определяется только для значений типа Some[A] (для вашего пользовательского типа A).

PartialFunction s выдает MatchError, когда вы пытаетесь применить их там, где они естьне определен.Поэтому, когда вы передаете PartialFunction, где определен обычный Function, вы должны убедиться, что ваша частичная функция никогда не будет вызываться с неопределяемым аргументом.Такой механизм очень полезен, например, для распаковки кортежей в коллекции: API

val tupleSeq: Seq[(Int, Int)] = // ...
val sums = tupleSeq.map { case (i1, i2) => i1 + i2 }

, которые запрашивают частичную функцию, такую ​​как collect фильтр-подобная операция над коллекциями, обычно вызывают isDefinedAt перед применениемчастичная функция.Там безопасно (и часто требуется) иметь частичную функцию, которая не определена для каждого входного значения.

Итак, вы видите, что хотя синтаксис близок к синтаксису match, он на самом делесовсем другая вещь, с которой мы имеем дело.

14 голосов
/ 24 августа 2011

Спецификация языка адресована в разделе 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].

6 голосов
/ 24 августа 2011

- Исправленный пост -

Хм, я не уверен, что вижу разницу, 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 {...} и {...}.

Update .После прочтения спецификации языка это кажется мне ошибкой.Я подал SI-4940 в трекер ошибок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...