Имеет ли смысл использовать сопоставление с образцом в 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 ответа

Решение

Обычно я бы написал так, как ты. (Несмотря на то, что сопоставление с образцом довольно эффективно, оно не так эффективно, как голова / хвост.) Вы бы использовали сопоставление с образцом, если

  1. Вы хотели попрактиковаться в сопоставлении с образцом
  2. Вы хотели MatchException вместо NoSuchElementException
  3. Вы собирались заполнить другие дела позже.

Есть несколько причин:

  1. Часть этой книги состоит в том, чтобы заставить вас думать в Scala (функциональных) терминах; сопоставление с образцом является функционально-программным эквивалентом.

  2. Сопоставление с образцом и функциональный подход являются естественным шаблоном в 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()
}
Другие вопросы по тегам