【问题标题】:Getters and setters to classes in Common LispCommon Lisp 中类的 getter 和 setter
【发布时间】:2016-08-20 05:43:52
【问题描述】:

我经常有一个由另一个类的列表组成的类。例如,我将有一个由向量​​组成的向量列表类。为了避免编写长语句,我编写了一个访问嵌入式类的方法。但是,此方法仅充当 getter;我不能用它来设置槽值。有没有办法使用方法来设置类槽值?

下面是一个最小的例子:

(defclass vector ()
  ((name :accessor vector-name
         :initarg :name)))

(defclass vector-list ()
  ((vectors :accessor vector-list-vectors
            :initarg :vectors)))

(defun make-vector-list ()
  (make-instance 'vector-list
    :vectors (list
               (make-instance 'vector :name 'v1)
               (make-instance 'vector :name 'v2))))

(defmethod access-vector-name ((vt vector-list) vector-idx)
  (vector-name (nth vector-idx (vector-list-vectors vt))))


;; returns V1
(print (access-vector-name (make-vector-list) 0))

;; Now, trying to set the same slot returns an error
;; How can I set the slot?
(setf (access-vector-name (make-vector-list) 0) 'new); --> error

【问题讨论】:

    标签: oop lisp common-lisp setter clos


    【解决方案1】:

    最简单的就是这样写:

    (setf (aref (access-vector-name ...) index) value)`
    

    但是如果你不想暴露你有数组/向量的事实,你可以定义一个自定义的 setf 扩展器。

    首先,只在你的类中将access-vector-name 定义为:reader。 那么:

    (defun (setf access-vector-name) (newval obj index)
      (setf (aref (access-vector-name obj) index) newval))
    

    如果意图隐藏底层实现,那么access-vector-name 可能是个坏名字。

    【讨论】:

      【解决方案2】:

      您只需要定义一个 setter 方法来执行此操作。但是,您的代码目前是不合法的:VECTORCL 包中定义的符号(实际上同时命名了一个函数和一个类型),因此定义一个名为 VECTOR 的类是非常非法的(而且是一个体面的实施会对此感到厌烦)。这是您的代码的一个版本,其中基本类重命名为 VEC,并带有一个 setter 方法。

      (defclass vec ()
        ;; Don't call it VECTOR since it's a function in CL
        ((name :accessor vec-name
               :initarg :name)))
      
      (defclass vec-list ()
        ((vecs :accessor vec-list-vecs
               :initarg :vecs)))
      
      (defun make-vec-list ()
        (make-instance 'vec-list
          :vecs (list
                 (make-instance 'vec :name 'v1)
                 (make-instance 'vec :name 'v2))))
      
      (defmethod access-vec-name ((vt vec-list) vec-idx)
        (vec-name (nth vec-idx (vec-list-vecs vt))))
      
      (defmethod (setf access-vec-name) (new (vt vec-list) vec-idx)
        (setf (vec-name (nth vec-idx (vec-list-vecs vt))) new))
      

      CLOS 没有预定义的宏来定义这样的访问器方法,在类定义之外:我不知道为什么,但也许是因为像这样的真正“纯”访问器的情况相对不常见。

      【讨论】:

      • 好吧,你可以命名一个类 VECTOR,如果它的符号属于另一个包......但这是挑剔
      猜你喜欢
      • 2021-09-13
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 2015-01-20
      • 2012-03-12
      • 2012-06-09
      • 1970-01-01
      相关资源
      最近更新 更多