是否可以像函数一样定义结构的一个插槽并访问插槽以使用该功能?如果是的话,怎么用呢?例如,像这样:
(defstruct problem
state
(player (defun getplayer (some-state) (findplayer 1 some-state)))
(points (defun getpoints (some-state someplayer) (findpoints someplayer some-state)))
)
答案 0 :(得分:2)
你所写的内容不起作用,但你可以这样做:
(defstruct problem () state)
(defgeneric getplayer (problem)
(:method ((p problem))
(find-player 1 (problem-state p))))
(defgeneric getpoints (problem player)
(:method ((p problem) player)
(findpoints player (problem-state p))))
答案 1 :(得分:2)
这也是你能做的好事:
(defclass get-player ()
((state :initarg :state :accessor state-of))
(:metaclass sb-mop:funcallable-standard-class))
(defmethod initialize-instance :after ((this get-player) &rest initargs)
(declare (ignore initargs))
(sb-mop:set-funcallable-instance-function
this (lambda ()
(format t "~&I am: ~s, my state is: ~s" this (state-of this)))))
(let ((get-player (make-instance 'get-player :state :initial-state)))
(funcall get-player)
(setf (state-of get-player) :advanced-state)
(funcall get-player))
;; I am: #<GET-PLAYER {10036104BB}>, my state is: :INITIAL-STATE
;; I am: #<GET-PLAYER {10036104BB}>, my state is: :ADVANCED-STATE
也就是说,您可以使用函数对象来控制它们捕获的变量。因此,由于您在示例代码中不需要problem
的实例来调用getplayer
(您只需要state
),因此这种方法可能很有趣。
答案 2 :(得分:2)
我会使用以下两种技术之一:
第一种方法是,不是在槽中存储函数,而是存储命名函数的符号。请注意,这假定命名函数在结构def本身之外的其他地方定义。
(Defstruct problem
State
(Points 'getpoints)
(Player 'getplayer))
这可以类似于:
的方式使用 (Defvar p (make-problem ...))
(Funcall (problem-points p) x)
(Funcall (problem-player p) x y)
这样做的原因是,当提供符号时,Funcall会在调用之前自动解析其fdefinition。第二种方法非常相似,但是代替表示命名函数的符号,槽直接设置为匿名函数(称为“lambda表达式”)。这种方法与您列出的示例有额外的相似之处,我是分配给槽值的函数是在结构的定义或实例化中定义的,并且不依赖于已在别处定义的函数。所以:
(Defstruct problem
State
(Points (lambda (arg0) (some-computation arg0)))
(Player (lambda (arg0 arg1) (other-computation arg0 arg1))))
然后:
(Defvar q (make-problem ...))
(Funcall (problem-points q) x)
(Funcall (problem-player q) x y)
希望有帮助!