Остановка метода от вызова: после
Скажем, у меня есть настройки кода, как показано ниже
(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)))