Как выполнить функцию на заданном месте

У меня есть список, который содержит некоторые символы и значения. Цель состоит в том, чтобы установить слот класса с помощью средства доступа, символ которого представлен в списке:

(defclass my-class ()
 ((attr :accessor attr)))

(let ((to-call '(attr "some-value"))
      (obj (make-instance 'my-class)))
 (setf `(,(car to-call) obj) (cadr to-call)))

Я пробовал через макрос:

(defmacro call-accessor (to-call)
 `(setf (,(car to-call) obj) "some-value"))

(let ((to-call '(attr "some-value"))
      (obj (make-instance 'my-class)))
 (call-accessor to-call))

Что тоже не получается, так как to-call это символ, а не список.

  • eval не работает с to-call является лексической переменной;
  • Это не возможно сделать let над макросом, чтобы дать ему список;
  • Я пробовал с with-slots а также with-accessors но проблема остается той же, потому что они тоже макросы.
  • Я рассмотрел макросы, которые объявляют другой макрос, и symbol-macrolet тоже.

Как я могу установить слот через аксессор, соответствующий символу в моем списке?

Спасибо.

3 ответа

Решение

Вызов функции доступа

Цель состоит в том, чтобы установить слот класса с помощью аксессора

Аксессор - это пара функций. Вы можете получить часть, которая устанавливает значение через FDEFINITION, Название функции представляет собой список (SETF accessor-name ), Это необычно: Common Lisp имеет в этом случае имена функций, которые не являются символами, а списками.

CL-USER 14 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (funcall (fdefinition `(setf ,(first to-call)))
                        (second to-call)
                        obj)
               (describe obj))

#<MY-CLASS 40200614FB> is a MY-CLASS
ATTR      "some-value"

Используя функцию call-accessor:

CL-USER 25 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (flet ((call-accessor (obj to-call)
                        (funcall (fdefinition `(setf ,(first to-call)))
                                 (second to-call)
                                 obj)))
                 (call-accessor obj to-call)
                 (describe obj)))

#<MY-CLASS 402000220B> is a MY-CLASS
ATTR      "some-value"

используя SETF с APPLY, чтобы скрыть вызов FDEFINITION

Использовать setf с вычисленным средством доступа, возможно, потребуется использовать apply Форма и пользовательская функция.

Что-то вроде call-accessor естественно, будет функцией, потому что она выполняет поиск во время выполнения и принимает значения. Попытка использовать макрос будет более полезной, если метод доступа будет известен во время компиляции.

CL-USER 23 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (flet (((setf my-setter) (new-value object accessor) 
                        (funcall (fdefinition `(setf ,accessor))
                                 new-value
                                 obj)))
                 (flet ((call-accessor (obj to-call)
                          (setf (apply #'my-setter obj (list (first to-call)))
                                (second to-call))))
                   (call-accessor obj to-call)
                   (describe obj))))

#<MY-CLASS 40200009AB> is a MY-CLASS
ATTR      "some-value"

Выбор структуры данных

Я думаю, что все в порядке, чтобы вычислить функции доступа и тому подобное. Там могут быть случаи использования для этого. CLOS был разработан, чтобы быть динамичным и отражающим, чтобы позволить эти вещи.

Ты можешь использовать setf из slot-value, используя символ имени слота в вашей паре данных:

(let ((to-call '(attr "some-value")))
  (setf (slot-value obj (first to-call)) (second to-call)))

Однако, используя slot-value напрямую обычно имеет смысл только тогда, когда вы спорите с внутренними объектами (такими как методы / комбинации инициализирующего экземпляра; или, возможно, вы работаете над каким-то механизмом сериализации).

Если это не так, вы используете объект просто как ассоциативную структуру данных. Я бы предложил вместо этого использовать alist, plist или hash-map.

Я согласен, что альтернативная структура, такая как hash-table вероятно, следует использовать. Но чтобы расширить ответ Сванте относительно slot-value, рабочий код просто:

(setf (slot-value obj 'attr) "some-value")
Другие вопросы по тегам