Остановка метода от вызова: после

Скажем, у меня есть настройки кода, как показано ниже

(defgeneric move (ship destination))

(defmethod move (ship destination)
  ;; do some fuel calculation here
)

(defmethod move :after ((ship ship) (dest station))
  ;; do things specific to landing on a station here
)

(defmethod move :after ((ship ship) (dest planet))
 ;; do things specific to landing on a planet here
)

Давайте теперь скажем, что я хочу переместить свой космический корабль на станцию, но расчет топлива приводит к отрицательному количеству топлива на корабле (т.е. для поездки недостаточно).

Есть ли способ для меня предотвратить :after квалификатор от вызова без необходимости сигнализировать об ошибке?

Если я не остановлю вызов, корабль будет перемещен на новое место без вычтенного топлива, что существенно нарушит игру.

2 ответа

Решение

Вы можете поместить расчет топлива в :AROUND метод и превратить два :AFTER методы в основные методы. :AROUND методы должны использовать CALL-NEXT-METHOD вручную, чтобы вызвать основной метод, так что вы можете сделать что-то вроде (when (sufficient-fuel) (call-next-method)) звонить только тогда, когда достаточно топлива.

Обратите внимание, что условия не обязательно являются ошибками. Ошибка - это особое условие, при котором нормальное выполнение программы не может продолжаться правильно без какого-либо вмешательства. Систему условий можно использовать и в других ситуациях.

Common Lisp также имеет catch а также throw для нелокальной передачи управления. Бросок будет пойман уловом в пределах его динамического экстента с использованием определенного тега улова.

Внешний :around метод устанавливает ловушку выхода для тега exit-move,

(defmethod move :around (ship destination)
  (catch 'exit-move (call-next-method)))

Внутренние методы, подобно основным методам, могут передавать управление catch, используя throw с правой меткой exit-move, Основной метод всегда будет использоваться внутри метода round, поэтому тег catch всегда будет доступен для его удаления.

(defmethod move (ship destination)
  (print (list :primary ship destination))
  (when (thing-happened-p)
   (throw 'exit-move nil)))
Другие вопросы по тегам