CommonLisp Функция для динамического поиска привязок в пакетах - PullRequest
0 голосов
/ 04 июля 2019

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

Как и в пакете B, я знаю, что существует пакет A, который имеет определенный класс, и я извлекаю все прямые слоты этого класса с помощью (в LispWorks):

(setq direct-slots (mapcar #'slot-definition-name
                           (class-direct-slots (class-of class-in-package-A))))

Теперь я хочу связать эти слоты с некоторыми значениями, используя MAPCAR:

(mapcar #'(lambda (slot) (list slot
                               (funcall slot class-in-package-A)))
             direct-slots)

Это не работает, так как я нахожусь в пакете B и нуждаюсь в точности пакета для вызова (funcall slot class-in-package-A), packageA::slot явно неверно. Есть ли функция для этого, которая ищет определенный символ в пакете?

1 Ответ

2 голосов
/ 04 июля 2019

Если у вас есть имя слота и вы хотите получить значение названного слота в каком-либо объекте, используйте slot-value:

(mapcar (lambda (slot-name)
          (slot-value some-object slot-name))
        slot-names)

Имена слотов являются символами, и они не будут волшебным образом терять свою упаковку, если вам случится оказаться в другой упаковке. Я думаю, что вы путаетесь в том, что вы думаете о средствах доступа, но это совсем другое (они используют что-то вроде slot-value внутри).

CL-USER> (defpackage #:foo
           (:use #:cl))
#<PACKAGE "FOO">
CL-USER> (defpackage #:bar
           (:use #:cl #:sb-mop))  ; in SBCL
#<PACKAGE "BAR">
CL-USER> (in-package #:foo)
#<PACKAGE "FOO">
FOO> (defclass afoo ()
       ((a :initarg :a)
        (b :initarg :b)))
#<STANDARD-CLASS FOO::AFOO>
FOO> (in-package #:bar)
#<PACKAGE "BAR">
BAR> (mapcar #'slot-definition-name
             (class-direct-slots (find-class 'foo::afoo)))
(FOO::A FOO::B)
BAR> (let ((slot-names (mapcar #'slot-definition-name
                               (class-direct-slots (find-class 'foo::afoo))))
           (obj (make-instance 'foo::afoo
                               :a 1
                               :b 2)))
       (mapcar (lambda (slot-name)
                 (slot-value obj slot-name))
               slot-names))
(1 2)

Как правило, вы должны использовать средства доступа в «пользовательском» коде, и вы должны знать, какие средства доступа существуют для данного объекта. Для пользовательского кода также не должно иметь значения, является ли что-то слотом прямой .

...