2011-08-23 6 views
12

En Scala, que puede hacer¿Cómo es una coincidencia de palabras omitidas en Scala?

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

Pero también se puede hacer la manera más rápida omitiendo match:

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

¿Cómo se apoya en Scala? ¿Es esto nuevo en 2.9? Lo he estado buscando, y puedo descubrir qué hace esto posible. ¿Es solo parte del compilador de Scala?

+0

De hecho, su primera variante no es válida. el artículo no está definido (y debería ser, no significaría un elemento de la lista). filtrar espera una función, debes escribir list.filter {item => item match ... No es solo coincidencia que desaparezca. –

+1

@didierd, edité la pregunta para abordar su punto válido, porque creo que todavía hay una pregunta interesante aquí. –

+0

@kipton gracias por la actualización. –

Respuesta

13

La dirección language specification que en la sección 8.5.Las porciones relevantes:

una función anónima pueden ser de nida por una secuencia de casos

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

Si el tipo esperado es scala.Functionk[S1, ..., Sk, R], la expresión se lleva a fi ser equivalente al anónimo función:

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

Si el tipo esperado es scala.PartialFunction[S, R], la expresión se toma para sea equivalente a la siguiente expresión creación de la instancia:

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

Así que escribir la expresión como PartialFunction o un Function influye en cómo se compila la expresión.

También trait PartialFunction [-A, +B] extends (A) ⇒ B por lo que una función parcial PartialFunction[A,B] también es Function[A,B].

+0

Me gusta esta respuesta. –

+0

Sí, creo que esto responde muy bien a la pregunta original. Más información: cuando el tipo esperado es una Función, como en el caso de 'Seq.filter', esto explica cómo' {case ...} 'se usa. Para otros métodos, como 'Seq.collect', el tipo esperado es una función parcial, y luego una expresión' {case ...} '* debe * ser requerida, en lugar de' x => x match {case ... } '; La respuesta de Jean-Philippe maneja ese caso, pero tenga en cuenta el extraño comportamiento del compilador descrito en mi respuesta. –

+0

Vamos a ir con esta respuesta como la respuesta aceptada porque cubre lo que el compilador está haciendo bastante bien. Gracias a todos por sus respuestas. –

18

Editar: partes de esta respuesta se equivocan; por favor, consulte huynhjl's answer.


Si se omite el match, que el compilador señal de que se está definiendo una función parcial. Una función parcial es una función que no está definida para cada valor de entrada. Por ejemplo, su función de filtro sólo se define por valores de tipo Some[A] (para el tipo personalizado A).

PartialFunction s arroja un MatchError cuando intentas aplicarlos donde no están definidos. Por lo tanto, usted debe asegurarse de que, cuando se pasa un PartialFunction donde se define un habitual Function, que su función parcial no será llamada con un argumento unhanded. Tal mecanismo es muy útil, p. para descomprimir tuplas de una colección:

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

API que piden una función parcial, al igual que la operación collect filtro-como en colecciones, por lo general isDefinedAt llamar antes de aplicar la función parcial. Allí, es seguro (y a menudo se desea) tener una función parcial que no está definida para cada valor de entrada.

Por lo tanto, puede ver que, aunque la sintaxis es similar a la de match, en realidad se trata de algo muy diferente.

+0

Lo que dices tiene sentido, pero según las pruebas que publiqué en mi respuesta, las dos expresiones parecen comportarse exactamente igual. ¿Podría ser un error? –

+0

@Kipton, resulta que '{case ...}' puede ser azúcar sintáctico para una función anónima 'x match {case ...}' - ver mi respuesta. – huynhjl

+0

@huynhjl, entiendo que, como se especificó, el compilador convierte '{case ...}' a una función de la forma 'x => x match {case ...}'. Lo extraño es que el compilador también hace lo contrario: convierte 'x => x match {case ...}' en una PartialFunction. Estoy bastante seguro de que esto no está en la especificación, y un error de compilación. Ver mi respuesta para más detalles. –

6

- revisado después -

Hmm, no estoy seguro de que veo una diferencia, 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 

Parece fg y se comportan exactamente el lo mismo que PartialFunctions.

Aquí hay otro ejemplo que demuestra la equivalencia:

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

Aún más interesante:

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

Así que hay un poco de carcasa especial a nivel del compilador para convertir entre x => x match {...} y justo {...}.

actualización. Después de leer las especificaciones del lenguaje, esto me parece un error. Yo presenté SI-4940 en el seguimiento de errores.

+0

¿Quisiste decir g.isDefinedAt y no f? ¿También es g una función parcial? –

+0

'g' y' f' ambos tienen tipo 'PartialFunction', sí. –

+0

Sí, entonces estoy confundido de cómo Scala sabe la diferencia. Debe estar al nivel del compilador. :/ –

Cuestiones relacionadas