Как прочитать слот из ссылки на объект, не оценивая указатель - PullRequest
2 голосов
/ 02 июля 2019

Я хотел получить значение атрибута из указателя внутри другого объекта, но доступ к нему без оценки ссылки вызвал у меня ошибку

When attempting to read the slot's value (slot-value), the slot
POS is missing from the object *NODE-1*.

Вот фрагмент кода, имитирующий ошибку:

(defclass node ()
  ((pos 
    :initarg :pos
    :initform '(0 0)
    :accessor pos)))

(defclass edge ()
  ((vertices
    :initarg :vertices
    :accessor vertices)))

(defparameter *node-1* (make-instance 'node))
(defparameter *node-2* (make-instance 'node :pos '(100 100)))
(defparameter *edge-1* (make-instance 'edge :vertices '(*node-1* *node-2*)))

После этого при вычислении этого выражения выдается ошибка

(slot-value (car (slot-value *edge-1* 'vertices)) 'pos)

Но у этого есть желаемое поведение

(slot-value (eval (car (slot-value *edge-1* 'vertices))) 'pos)

Я уже знаю, что eval используется для безобразных хаков, поэтому я пытаюсь найти умный способ сделать то, что мне нужно.

1 Ответ

5 голосов
/ 02 июля 2019

При попытке прочитать значение слота (slot-value), слот POS отсутствует в объекте *NODE-1*

*node-1* не является экземпляром CLOS.Это символslot-value нужен экземпляр CLOS.Таким образом, попытка вычислить значение слота символа не имеет смысла.

Примечание: objects в Common Lisp

В сообщении об ошибке термин объект *NODE-1* означает конкретный символьный объект во время выполнения.Символы тоже объекты.Они не являются объектами CLOS, то есть они не являются экземплярами CLOS класса CLOS.Но обычно в Common Lisp даже символ или строка считаются объектами .

Почему это символ?

Вы задаетеслот vertices будет иметь значение '(*node-1* *node-2*).Это буквальный список из двух символов, так как вы процитировали список.

CL-USER 152 > '(*node-1* *node-2*)
(*NODE-1* *NODE-2*)

CL-USER 153 > (mapcar #'type-of *)
(SYMBOL SYMBOL)

Один использует объекты напрямую

Если вы хотите вычислить список фактических значенийиз этих символов в качестве переменных вам необходимо вычислить список вычисляемых значений:

CL-USER 154 > '((+ 1 2))
((+ 1 2))

CL-USER 155 > (list (+ 1 2))
(3)

CL-USER 160 > (list *node-1* *node-2*)
(#<NODE 402032A2C3> #<NODE 402032B98B>)

CL-USER 161 > (mapcar #'type-of *)
(NODE NODE)

Функция list создает новый список со своими аргументами в качестве содержимого.

Получениезначение символа: используйте SYMBOL-VALUE

(symbol-value '*node-1*)
...