开发者

How is a match word omitted in Scala?

开发者 https://www.devze.com 2023-03-30 11:24 出处:网络
In Scala, you can do list.filter { item => item match { case Some(foo) => foo.bar > 0 } } But you can also do the quicker way by omitting match:

In Scala, you can do

list.filter { item =>
    item match {
      case Some(foo) => foo.bar > 0
    }
}

But you can also do the quicker way by omitting match:

list.filter {
  case Some(foo) => foo.bar > 0
}

How is this supported in Scala? Is this new in 2.9? I have been looking for it, and I can figure out what 开发者_如何学运维makes this possible. Is it just part of the Scala compiler?


Edit: parts of this answer are wrong; please refer to huynhjl's answer.


If you omit the match, you signal the compiler that you are defining a partial function. A partial function is a function that is not defined for every input value. For instance, your filter function is only defined for values of type Some[A] (for your custom type A).

PartialFunctions throw a MatchError when you try to apply them where they are not defined. Therefore, you should make sure, when you pass a PartialFunction where a regular Function is defined, that your partial function will never be called with an unhanded argument. Such a mechanism is very useful e.g. for unpacking tuples in a collection:

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

APIs which ask for a partial function, like the collect filter-like operation on collections, usually call isDefinedAt before applying the partial function. There, it is safe (and often wanted) to have a partial function that is not defined for every input value.

So you see that although the syntax is close to that of a match, it is actually quite a different thing we're dealing with.


The language specification addresses that in section 8.5. The relevant portions:

An anonymous function can be defined by a sequence of cases

{ case p1 => b1 ... case pn => bn }

If the expected type is scala.Functionk[S1, ..., Sk, R] , the expression is taken to be equivalent to the anonymous function:

(x1 : S1, ..., xk : Sk) => (x1, ..., xk) match {
  case p1 => b1 ... case pn => bn
}

If the expected type is scala.PartialFunction[S, R], the expression is taken to be equivalent to the following instance creation expression:

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
  }
}  

So typing the expression as PartialFunction or a Function influences how the expression is compiled.

Also trait PartialFunction [-A, +B] extends (A) ⇒ B so a partial function PartialFunction[A,B] is also a Function[A,B].


-- Revised post --

Hmm, I'm not sure I see a difference, 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

It seems f and g behave exactly the same as PartialFunctions.

Here's another example demonstrating the equivalence:

Seq(1, "a").collect(x => x match { case s: String => s }) // evaluates to Seq(a)

Even more interesting:

// 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 }}

So there's some special casing at the compiler level to convert between x => x match {...} and just {...}.

Update. After reading the language spec, this seems like a bug to me. I filed SI-4940 in the bug tracker.

0

精彩评论

暂无评论...
验证码 换一张
取 消