Имеет ли смысл использовать сопоставление с образцом в Scala с действительно простыми случаями?
В "Программирование в Scala, второе издание" на странице 410 вы можете найти класс Simulation, который имеет следующий метод:
private def next() {
(agenda: @unchecked) match {
case item :: rest =>
agenda = rest
curtime = item.time
item.action()
}
}
Мне любопытно, почему Одерский реализовал это с помощью сопоставления с образцом, а не просто так:
private def next() {
val item = agenda.head
agenda = agenda.tail
curtime = item.time
item.action()
}
Является ли сопоставление с образцом настолько эффективным, что это вообще не имеет значения? Или это был просто не такой идеальный пример?
4 ответа
Обычно я бы написал так, как ты. (Несмотря на то, что сопоставление с образцом довольно эффективно, оно не так эффективно, как голова / хвост.) Вы бы использовали сопоставление с образцом, если
- Вы хотели попрактиковаться в сопоставлении с образцом
- Вы хотели
MatchException
вместоNoSuchElementException
- Вы собирались заполнить другие дела позже.
Есть несколько причин:
Часть этой книги состоит в том, чтобы заставить вас думать в Scala (функциональных) терминах; сопоставление с образцом является функционально-программным эквивалентом.
Сопоставление с образцом и функциональный подход являются естественным шаблоном в Scala и допускают такие вещи, как параллелизм естественным образом; изучите этот шаблон, и ваши программы Scala будут готовы к более сложному использованию.
Сопоставление с образцом более идиоматично в Scala и легче защищает вас от граничных условий.
В коде
private def next() {
val item = agenda.head
agenda = agenda.tail
curtime = item.time
item.action()
}
И то и другое agenda.head
а также agenda.tail
бросит NoSuchElementException
исключение, если agenda
это пустой список, поэтому, чтобы он действительно работал, нужно добавить проверку для этого.
В версии для сопоставления с шаблоном на самом деле есть похожая проблема (как отмечается в комментариях), но я считаю, что исправление чище, так как все, что вам нужно сделать, это добавить другой шаблон:
private def next() {
(agenda: @unchecked) match {
case item :: rest =>
agenda = rest
curtime = item.time
item.action()
case _ => {}
}
}
Я думаю, во-первых, исключения не являются проблемой, вероятно, есть некоторая проверка перед вызовом этого "следующего" метода. На самом деле, это, вероятно, и является причиной "неконтролируемой" аннотации, так что он действительно не может поставить дополнительную case _ =>
, Я думаю, что причина была в том, что он хотел использовать "не применять". Альтернатива здесь без сопоставления с образцом, но и без head
а также tail
может быть что-то вроде:
private def next() {
val item :: rest = agenda
agenda = rest
curtime = item.time
item.action()
}