2009-10-05 18 views
8

Ho due domande riguardanti la classe di casi '::'.scale case classes domande

:: può essere utilizzato come

case head :: tail => ... 

Come funziona? Significato, qual è esattamente il flusso che Scala usa per abbinare un'istanza di List con la classe :: case? Dato che ho un MyClass di classe, con operatore op, è possibile creare un caso classe chiamata op che posso usare come:

case foo op bar => .... 

?

+2

Duplicato di http://stackoverflow.com/questions/1059145/how-is-this-case-class-match-pattern-working, veramente. –

+0

la mia domanda non riguardava solo il modo in cui '::' è tra le variabili, ma anche il modo in cui una classe case può eguagliare istanze di un'altra classe (la ragione è che List # :: crea istanze di :: case class) – IttayD

risposta

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

ottima risposta! quindi il trucco è che List # :: restituisce un'istanza della classe case ::. – IttayD

3

E 'dettagliato nella pagina 301 del Programming in Scala, A proposito di pattern matching sul 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

In realtà, il fatto che :: è una classe di casi è solo la metà della risposta. Il motivo per cui questo funziona nella corrispondenza dei modelli è che esiste un estrattore per object ::, che viene generato automaticamente quando viene definita una classe case. Convenientemente, ::. Unpply restituisce una lista, perché :: estende l'elenco. Se si desidera utilizzare lo stesso trucco per gli elenchi, tuttavia, non sarà possibile estendere l'elenco, poiché è finale. Quello che puoi fare è definire un oggetto con il metodo Unpply appropriato, che ha la firma di ritorno prevista. Per esempio, per abbinare il ultima elemento di una lista, si può fare:

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

L'estrattore deve restituire un opzione, che contiene una tupla di due elementi decostruiti.

+0

Non credo che si applichi qui in modo errato scala> val l = Lista (1, 2, 3) l: Lista [Int] = Elenco (1, 2, 3) scala> scala.::ununitario (L) : 6: errore: mancata corrispondenza di tipo; trovato: Lista [Int] richiesto: :: val r = scala.::(1, Nil) r [?]: :: [Int] = Lista (1) scala> scala. ::. unapply (r) res7: alcuni [List [Int]] = Alcuni (List()) così inapplicabile funziona solo se effettivamente costruito dalla classe case, non per un elenco generale. – IttayD

+0

Non c'è niente di speciale riguardo a unapply creata da una classe di case. Si noti che List è astratto e in realtà qualsiasi elenco non vuoto è un'istanza di scala. :: List (1) .isInstanceOf [:: [Int]] Ciò significa che in realtà ciò che si sta verificando in pattern è in realtà di scala. :: (a meno che non sia Nil). Si noti inoltre che non appena si ridefinisce in modo non valido per ::, la corrispondenza del modello per le pause Elenchi: oggetto :: {def unapply = false} – vdichev

0

Il testo citato da eed3si9n è a p. 331 nell'edizione PDF di "Programming in Scala" (1 ° ed.)