scala case классы вопросы

У меня есть два вопроса относительно класса case '::'.

:: можно использовать как

case head :: tail => ...

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

case foo op bar => ....

?


person IttayD    schedule 05.10.2009    source источник
comment
Дубликат stackoverflow. com/questions/1059145/, действительно.   -  person Daniel C. Sobral    schedule 05.10.2009
comment
мой вопрос заключался не только в том, как '::' находится между переменными, но и в том, как класс case может соответствовать экземплярам другого класса (причина в том, что List#:: создает экземпляры класса :: case)   -  person IttayD    schedule 07.10.2009
comment
Текст, процитированный eed3si9n, находится на с. 331 в PDF-издании Programming in Scala (1-е изд.)   -  person Eugen Labun    schedule 20.12.2010


Ответы (3)


Это подробно описано на странице 301 Программирование на Scala, О сопоставлении с образцом на Lists.

Шаблон "против" x :: xs является частным случаем шаблона инфиксной операции. Вы уже знаете, что в виде выражения инфиксная операция эквивалентна вызову метода. Для шаблонов правила другие: если рассматривать как шаблон, инфиксная операция, такая как p op q, эквивалентна op(p, q). То есть инфиксный оператор op рассматривается как шаблон конструктора. В частности, шаблон cons, такой как x :: xs, обрабатывается как ::(x, xs). Это намекает на то, что должен быть класс с именем ::, соответствующий конструктору шаблона. Действительно есть такой класс. Он называется scala.:: и это именно тот класс, который строит непустые списки.

person Eugene Yokota    schedule 06.10.2009

На самом деле тот факт, что :: является case-классом, — это только половина ответа. Причина, по которой это работает при сопоставлении с образцом, заключается в том, что существует извлекатель для объекта ::, который генерируется автоматически при определении класса case. Удобно, что ::.unapply возвращает список, потому что :: расширяет список. Однако, если вы хотите использовать тот же прием для списков, вы не сможете расширить список, потому что он окончательный. Что вы можете сделать, так это определить объект с соответствующим методом 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!"
}

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

person vdichev    schedule 06.10.2009
comment
Я не думаю, что здесь применимо unapply scala› val l = List(1, 2 , 3) ​​l: List[Int] = List(1, 2, 3) scala› scala.::.unapply(l) ‹console› :6: ошибка: несоответствие типов; найдено: List[Int] required: ::[?] val r = scala.::(1, Nil) r: ::[Int] = List(1) scala› scala.::.unapply(r) res7: Some[List[Int]] = Some(List()), поэтому unapply работает только в том случае, если он фактически создан классом case, а не для общего списка. - person IttayD; 07.10.2009
comment
Нет ничего особенного в неприменении, которое создает класс case. Обратите внимание, что список является абстрактным, и на самом деле любой непустой список является экземпляром scala.:: List(1).isInstanceOf[::[Int]] Это означает, что то, что вы сопоставляете в шаблонах, на самом деле является экземплярами scala.: : (если это не Nil). Обратите также внимание, что как только вы переопределяете unapply только для ::, сопоставление шаблонов для списков прерывается: object :: {def unapply = false} - person vdichev; 09.10.2009

person    schedule
comment
отличный ответ! так что хитрость в том, что List#:: возвращает экземпляр класса case ::. - person IttayD; 06.10.2009