Common lisp 如何将关键字转换为适合访问插槽的符号?
我有一个有很多槽的班。我还有一个构建器函数来创建该类的对象,这样,将下面的列表Common lisp 如何将关键字转换为适合访问插槽的符号?,common-lisp,Common Lisp,我有一个有很多槽的班。我还有一个构建器函数来创建该类的对象,这样,将下面的列表”(:id“john”:name“john Doe”:age 42)传递给该函数将使用这些值构造一个新对象。我将使用该函数生成多个对象,使用列表列表 如何将关键字(如:id转换为slot-VALUE可以使用的插槽名称 谢谢。查找符号和符号名称功能将对您有所帮助。如果defclass和slot value发生在同一个包中,则可以按如下方式使用这些功能: (定义人员() ((id:initarg:id) (名称:inita
”(:id“john”:name“john Doe”:age 42)
传递给该函数将使用这些值构造一个新对象。我将使用该函数生成多个对象,使用列表列表
如何将关键字(如:id
转换为slot-VALUE
可以使用的插槽名称
谢谢。查找符号和符号名称功能将对您有所帮助。如果
defclass
和slot value
发生在同一个包中,则可以按如下方式使用这些功能:
(定义人员()
((id:initarg:id)
(名称:initarg:name)
(年龄:initarg:age)))
(插槽值(生成实例的人:id“john”:name“john Doe”:42岁)
(查找符号(符号名称:id)))
如果defclass
和slot value
发生在两个不同的包中,则需要给出find symbol
发生defclass
的包的名称:
(in-package #:common-lisp-user)
(defpackage #:foo
(:use #:common-lisp)
(:export #:person))
(defpackage #:bar
(:use #:common-lisp #:foo))
(in-package #:foo)
(defclass person ()
((id :initarg :id)
(name :initarg :name)
(age :initarg :age)))
(in-package #:bar)
(slot-value (make-instance 'person :id "john" :name "John Doe" :age 42)
(find-symbol (symbol-name :id) 'foo))
(查找符号名称和可选(软件包(sane软件包))
函数:返回包中名为STRING的符号。如果找到这样的符号,则第二个值为:INTERNAL、:EXTERNAL或:INHERITED,以指示如何访问该符号。如果未找到符号,则两个值均为零
(符号名称符号)
函数:以字符串形式返回符号的名称
如果关键字是类的initargs,那么您可以通过APPLY
调用MAKE-INSTANCE
:
(defclass person ()
((id :initarg :id )
(name :initarg :name)
(age :initarg :age )))
CL-USER > (mapcar
(lambda (initargs)
(apply #'make-instance 'person initargs))
'((:id "john" :name "John Doe" :age 42)
(:id "mary" :name "Mary Doe" :age 42)))
(#<PERSON 402027AB7B> #<PERSON 402027AC33>)
(定义人员()
((id:initarg:id)
(名称:initarg:name)
(年龄:initarg:age)))
CL-USER>(地图车)
(lambda(initargs)
(应用#“创建实例”person initargs))
(:id“john”:name“john Doe”:42岁)
(:id“mary”:姓名“mary Doe”:42岁)
(# #)
我对CL这种愚蠢行为的解决方案是:
(defun locate-symbol
(inst kw)
(let* ((slot-name (symbol-name kw))
(slot-def (find slot-name
(clos:compute-slots (class-of inst))
:test #'(lambda (name sd)
(string= name
(symbol-name (clos:slot-definition-name sd)))))))
(if slot-def
(clos:slot-definition-name slot-def)
(error "Can't find a slot definition named ~s." slot-name))))
(defun gets
(self slot-name)
"Get a value of a slot by its name (keyword)"
(slot-value self (locate-symbol self slot-name)))
(defun sets!
(self slot-name value)
"Set a value of a slot by its name (keyword)"
(setf (slot-value self (locate-symbol self slot-name))
value))
现在你可以做:
(defvar obj (make-instance '<some-class>))
(sets! obj :some-slot "some value")
(format t "-> ~a~%" (gets obj :some-slot))
(defvar obj(生成实例'))
(设置!对象:某个插槽“某个值”)
(格式t->~a~%“(获取对象:某个插槽))
我意识到这一点很古老,但我认为最重要的一点是:
不要那样使用插槽值强>
要获取访问器,请使用:accessor
或:reader
插槽选项,要将值传递给构造函数,请使用:initarg
:
(defclass foo ()
((bar :accessor foo-bar :initarg :bar)))
这意味着:创建一个名为foobar
的getter方法和setf扩展器,并使用名为:bar的关键字参数来生成实例
来初始化此插槽的值
现在您可以像这样实例化这样的对象:
(make-instance 'foo :bar "quux")
(foo-bar some-foo)
或者,如果您得到initargs的属性列表(如Rainer所示):
然后可以获得如下值:
(make-instance 'foo :bar "quux")
(foo-bar some-foo)
并像往常一样使用setf
进行设置:
(setf (foo-bar some-foo) "wobble")
如果使用:reader
而不是:accessor
,则不允许进行设置。这通常有助于传达不变性的意图
Slot value
确实适用于对象生命周期中的特殊情况,例如使用初始化实例的方法时。这是一个高级主题。我喜欢你的“更实用”的方法。@WhiteCat是你关于如何使用这些列表调用make instance
的问题?我对你的问题有不同的理解,因为问题的标题和主体说“我如何将关键字转换为适合访问插槽的符号?”和“我如何将关键字(如:id)转换为slot-VALUE
可以使用的插槽名称?”。如果您的真正目标只是调用生成实例
,而不是插槽值
,那么Rainer Joswig的解决方案就是一条出路。@dkim:我的问题与书面内容完全一样,您的回答是正确的。我以前试过使用(查找符号…
),但使用了关键字作为包,所以不起作用。Rainer的回答给了我另一个视角,一个我没有考虑的问题,那就是正确的解决方案。谢谢两位。