2009-10-05 6 views
8

У меня есть два вопроса относительно класса класса «::».scala case classes вопросы

:: могут быть использованы в качестве

case head :: tail => ... 

Как это работает? Смысл, что такое поток, который использует Scala для соответствия экземпляру List с классом :: case? Учитывая, что у меня есть класс MyClass, с оператором оп, я могу создать именованный цит случай класса, который можно использовать как:

case foo op bar => .... 

?

+2

Дубликат http://stackoverflow.com/questions/1059145/how-is-this-case-class-match-pattern-working, действительно. –

+0

мой вопрос заключался не только в том, как получилось «::» между переменными, но и как класс case может соответствовать экземплярам другого класса (причина в том, что List # :: создает экземпляры класса case) – IttayD

ответ

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

отличный ответ! поэтому трюк заключается в том, что List # :: возвращает экземпляр класса case ::. – IttayD

3

Это подробно описано в странице 301 Programming in Scala, О шаблоне на List с.

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

Фактически, тот факт, что :: является классом case, является только половиной ответа. Причина, по которой это работает в сопоставлении с образцом, заключается в том, что для объекта :: существует экстрактор, который генерируется автоматически при определении класса case. Удобно, ::. Unapply возвращает список, потому что :: extends List. Если вы хотите использовать тот же трюк для списков, вы не сможете расширить список, потому что это final. Что вы можете сделать, так это определить объект с соответствующим методом unapply, который имеет ожидаемую обратную подпись. Например, в соответствии с последним элементом списка, вы можете сделать:

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

экстрактора должен возвращать вариант, который содержит кортеж из двух деконструктивистских элементов.

+0

Я не думаю, что здесь применяется unapply scala> val l = List (1, 2, 3) l: Список [Int] = Список (1, 2, 3) scala> scala.::.unapply(l) : 6: ошибка: тип несоответствия; найдено: Список [Int] требуется: :: вал г = scala.::(1, Nil) г [?]: :: [Int] = Список (1) Скала> :: Скала.. unapply (r) res7: Some [List [Int]] = Some (List()) поэтому unapply работает только в том случае, если фактически построено классом case, а не для общего списка. – IttayD

+0

Нет ничего особенного в том, что unapply создает класс case. Обратите внимание, что List является абстрактным, и фактически любой непустой список является экземпляром scala. :: Список (1) .isInstanceOf [:: [Int]] Это означает, что то, что вы сопоставляете в шаблонах, является фактически экземплярами scala. :: (если это не Nil). Также обратите внимание, что как только вы только переопределите unapply для ::, сопоставление шаблонов для перерывов Списки: объект :: {def unapply = false} – vdichev

0

Текст, цитируемый eed3si9n, приведен на стр. 331 в PDF-редакции «Программирование в Scala» (1-е изд.)