Common Lisp:如何覆盖插槽访问器?
Common Lisp: how to override slot accessors?
我想控制值在槽中的保存方式以及读取槽时返回的内容。这是我的 class 定义:
(defclass object ()
((name :accessor name-access
:initform 'noname
:initarg :name)
(value :accessor value-access
:initform 10
:initarg :value)))
我这样创建对象:
(setf obj1 (make-instance 'object))
这是我获取插槽值的方式 name
:
(name-access obj1)
以及我如何设置新值:
(setf (name-access obj1) 'realname)
重写此访问器函数(或方法)以便能够对对象进行某些更改(写入时)并控制返回值的正确方法是什么?
谢谢。
您可以手动定义获取和设置插槽的方法:
(defclass foo ()
((name :initform 'noname
:initarg :name)))
(defgeneric name-access (foo)
(:method ((foo foo))
(format t "~&Getting name.~%")
(slot-value foo 'name)))
(defgeneric (setf name-access) (name foo)
(:method (name (foo foo))
(format t "~&Setting a new name.~%")
(setf (slot-value foo 'name) name)))
(defparameter *foo* (make-instance 'foo))
(name-access *foo*)
; Getting name.
;=> NONAME
(setf (name-access *foo*) 'some-name)
; Setting a new name.
;=> SOME-NAME
(name-access *foo*)
; Getting name.
;=> SOME-NAME
本书Practical Common Lisp goes through these in chapter 17。你应该读一下。
您可以扩展 DEFCLASS
:
定义的访问器方法
CL-USER 66 > (defclass object ()
((name :accessor name-access
:initform 'noname
:initarg :name)
(value :accessor value-access
:initform 10
:initarg :value)))
#<STANDARD-CLASS OBJECT 4220014953>
写作,使用:before
方法:
CL-USER 67 > (defmethod (setf name-access) :before (new-value (o1 object))
(print "hi"))
#<STANDARD-METHOD (SETF NAME-ACCESS) (:BEFORE) (T OBJECT) 40202283BB>
阅读,使用:around
方法:
CL-USER 68 > (defmethod name-access :around ((o1 object))
(let ((name (call-next-method)))
(values name (length (symbol-name name)))))
#<STANDARD-METHOD NAME-ACCESS (:AROUND) (OBJECT) 4020061213>
示例:
CL-USER 69 > (let ((o1 (make-instance 'object)))
(setf (name-access o1) 'foobar)
(name-access o1))
"hi" ; side effect
FOOBAR ; return value 1
6 ; return value 2
我想控制值在槽中的保存方式以及读取槽时返回的内容。这是我的 class 定义:
(defclass object ()
((name :accessor name-access
:initform 'noname
:initarg :name)
(value :accessor value-access
:initform 10
:initarg :value)))
我这样创建对象:
(setf obj1 (make-instance 'object))
这是我获取插槽值的方式 name
:
(name-access obj1)
以及我如何设置新值:
(setf (name-access obj1) 'realname)
重写此访问器函数(或方法)以便能够对对象进行某些更改(写入时)并控制返回值的正确方法是什么?
谢谢。
您可以手动定义获取和设置插槽的方法:
(defclass foo ()
((name :initform 'noname
:initarg :name)))
(defgeneric name-access (foo)
(:method ((foo foo))
(format t "~&Getting name.~%")
(slot-value foo 'name)))
(defgeneric (setf name-access) (name foo)
(:method (name (foo foo))
(format t "~&Setting a new name.~%")
(setf (slot-value foo 'name) name)))
(defparameter *foo* (make-instance 'foo))
(name-access *foo*)
; Getting name.
;=> NONAME
(setf (name-access *foo*) 'some-name)
; Setting a new name.
;=> SOME-NAME
(name-access *foo*)
; Getting name.
;=> SOME-NAME
本书Practical Common Lisp goes through these in chapter 17。你应该读一下。
您可以扩展 DEFCLASS
:
CL-USER 66 > (defclass object ()
((name :accessor name-access
:initform 'noname
:initarg :name)
(value :accessor value-access
:initform 10
:initarg :value)))
#<STANDARD-CLASS OBJECT 4220014953>
写作,使用:before
方法:
CL-USER 67 > (defmethod (setf name-access) :before (new-value (o1 object))
(print "hi"))
#<STANDARD-METHOD (SETF NAME-ACCESS) (:BEFORE) (T OBJECT) 40202283BB>
阅读,使用:around
方法:
CL-USER 68 > (defmethod name-access :around ((o1 object))
(let ((name (call-next-method)))
(values name (length (symbol-name name)))))
#<STANDARD-METHOD NAME-ACCESS (:AROUND) (OBJECT) 4020061213>
示例:
CL-USER 69 > (let ((o1 (make-instance 'object)))
(setf (name-access o1) 'foobar)
(name-access o1))
"hi" ; side effect
FOOBAR ; return value 1
6 ; return value 2