2009-10-05 21 views
8

Tengo dos preguntas con respecto a la clase de caso '::'.preguntas de las clases de scala case

:: puede ser utilizado como

case head :: tail => ... 

¿Cómo funciona? Es decir, ¿cuál es exactamente el flujo que usa Scala para hacer coincidir una instancia de List con la clase :: case? Dado que tengo una clase MiClase, con el operador op, puedo crear una clase llamada op caso de que puedo utilizar como:

case foo op bar => .... 

?

+2

Duplicado de http://stackoverflow.com/questions/1059145/how-is-this-case-class-match-workwork-working, De Verdad. –

+0

mi pregunta no era solo por qué '::' se encuentra entre las variables, sino también cómo una clase case puede coincidir con instancias de otra clase (la razón es que List # :: crea instancias de :: case class) – IttayD

Respuesta

5
 scala> abstract class Stack { 
    |  def push(n :Int):Stack 
    | } 
     defined class Stack 

    scala> final case class push(st :Stack,hd :Int) extends Stack { 
    |  override def push(n :Int):Stack = new push(this,n) 
    | } 
    defined class push 

    scala> object NullStack extends Stack { 
    |  override def push(n :Int):Stack = new push(null,n) 
    | } 
    defined module NullStack 

    scala> val s = NullStack.push(1).push(2) 
    s: Stack = push(push(null,1),2) 

    scala> def test(s :Stack) = s match { case st push i => println(st +"push " + i) } 
    test: (Stack)Unit 

    scala> test(s) 
    push(null,1)push 2 
+0

¡excelente respuesta! así que el truco es que List # :: devuelve una instancia de la clase case ::. – IttayD

3

Es detalla en la página 301 del Programming in Scala, Acerca de patrones sobre List s.

The "cons" pattern x :: xs is a special case of an infix operation pattern. You know already that, when seen as an expression, an infix operation is equivalent to a method call. For patterns, the rules are different: When seen as a pattern, an infix operation such as p op q is equivalent to op(p, q) . That is, the infix operator op is treated as a constructor pattern. In particular, a cons pattern such as x :: xs is treated as ::(x, xs) . This hints that there should be a class named :: that correspond to the pattern constructor. Indeed there is such a class. It is named scala.:: and is exactly the class that builds non-empty lists.

2

En realidad, el hecho de que :: es una clase de caso es solo la mitad de la respuesta. La razón por la que esto funciona en la coincidencia de patrones es que existe un extractor para object ::, que se genera automáticamente cuando se define una clase de caso. Convenientemente, ::. Unapply devuelve una lista, porque :: extends List. Sin embargo, si desea utilizar el mismo truco para Listas, no podrá extender la Lista, porque es final. Lo que puede hacer es definir un objeto con el método apropiado de aplicación, que tiene la firma de devolución esperada. Por ejemplo, para que coincida con la última elemento de una lista, que puede hacer:

object ::> {def unapply[A] (l: List[A]) = Some((l.init, l.last))} 

List(1, 2, 3) match { 
    case _ ::> last => println(last) 
} 

(1 to 9).toList match { 
    case List(1, 2, 3, 4, 5, 6, 7, 8) ::> 9 => "woah!" 
} 
(1 to 9).toList match { 
    case List(1, 2, 3, 4, 5, 6, 7) ::> 8 ::> 9 => "w00t!" 
} 

El extractor debe devolver una opción, que contiene una tupla de los dos elementos de la deconstrucción.

+0

No creo que la aplicación aplique aquí scala> val l = Lista (1, 2, 3) l: Lista [Int] = Lista (1, 2, 3) scala> scala.::.unapply(l) : 6: error: no coincide; encontrado: Listado [Int] requerido: :: val r = scala.::(1, cero) r [?]: :: [Int] = Lista (1) Scala> Scala. ::. unapply (r) res7: Some [List [Int]] = Some (List()) así que unapply funciona solo si está construido por la clase case, no para una lista general. – IttayD

+0

No hay nada especial acerca de la aplicación que crea una clase de caso. Tenga en cuenta que List es abstracto y en realidad cualquier lista no vacía es una instancia de scala. :: List (1) .isInstanceOf [:: [Int]] Lo que significa que lo que está buscando en los patrones es en realidad instancias de scala. :: (a menos que sea Nil). Observe también que tan pronto como solo redefine una aplicación para ::, la coincidencia de patrones para Listas rompe: objeto :: {def unapply = false} – vdichev

0

El texto citado por eed3si9n está en la p. 331 en la edición en PDF de "Programación en Scala" (1ª edición)

Cuestiones relacionadas