首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用点表示法访问CLOS槽

使用点表示法访问CLOS槽
EN

Stack Overflow用户
提问于 2016-08-27 16:31:30
回答 3查看 389关注 0票数 2

访问类槽时,而不是编写

代码语言:javascript
复制
(defmethod get-name ((somebody person) (slot-value somebody 'name))

是否可以使用点表示法,也就是C++,即

代码语言:javascript
复制
(defmethod get-name ((somebody person) somebody.name) ?

否则,当方法中有许多槽操作时,(slot-value...会创建大量样板代码。

我今天已经想出了答案,我只是把它作为问答发表出来,但如果有更好的解决方案或我期望的解决方案有问题,请随意添加新的答案或评论。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-31 12:25:27

您不应该手工编写访问器,也不应该使用slot-value (在对象生命周期函数之外,访问器可能还没有创建)。改为使用类插槽选项:

代码语言:javascript
复制
(defclass foo ()
  ((name :reader foo-name
         :initarg :name)
   (bar :accessor foo-bar
        :initarg :bar)))

现在您可以使用命名访问器:

代码语言:javascript
复制
(defun example (some-foo new-bar)
  (let ((n (foo-name some-foo))
        (old-bar (foo-bar some-foo)))
    (setf (foo-bar some-foo) new-bar)
    (values n old-bar)))

通常,您希望类是“不可变的”,然后使用:reader而不是:accessor,这只会创建读取器,而不是扩展。

票数 3
EN

Stack Overflow用户

发布于 2016-08-28 03:35:07

访问提供了一个点符号读取器宏,用于访问插槽(以及哈希表和其他东西)。在通过调用( access :Enable-点式语法)启用读取器宏之后,您将能够使用#D来访问在其他语言中流行的点语法的槽名。

代码语言:javascript
复制
(defclass person ()
  ((name :initarg :name :reader name)))

CL-USER> (access:enable-dot-syntax)
; No values
CL-USER> (defvar *foo* (make-instance 'person :name "John Smith"))
*FOO*
CL-USER> #D*foo*
#<PERSON #x302001F1E5CD>
CL-USER> #D*foo*.name
"John Smith"

如果不想使用读取器宏,也有一个with-dot

代码语言:javascript
复制
CL-USER> (access:with-dot () *foo*.name)
"John Smith"
票数 6
EN

Stack Overflow用户

发布于 2016-08-27 16:31:30

最简单的解决方案似乎是加载.的读取器宏,这样就可以将(slot-value somebody 'name)编写为.somebody.name,我的策略是将somebody.name读入为字符串(我们需要定义一个不终止的宏字符,以便读取器不停止中间字符串),然后处理该字符串以构造适当的(slot-value...

我需要两个助手函数:

代码语言:javascript
复制
(defun get-symbol (str)
  "Make an uppercase symbol"
  (intern (string-upcase str)))

(defun split-string (str sep &optional (start 0))
  "Split a string into lists given a character separator"
  (let ((end (position sep str :start start)))
    (cons (subseq str start end) (if end (split-string str sep (1+ end))))))

然后我可以定义我的读取器宏:

代码语言:javascript
复制
(defun dot-reader (stream char)
  (declare (ignore char))
  (labels ((make-query (list)
             (let ((car (car list))
                   (cdr (cdr list)))
               (if cdr `(slot-value ,(make-query cdr) (quote ,(get-symbol car)))
                   (get-symbol car)))))
    (make-query (nreverse (split-string (symbol-name (read stream)) #\.)))))

最后,我需要注册这个读取器宏:

代码语言:javascript
复制
(set-macro-character #\. #'dot-reader t)

现在可以写:

代码语言:javascript
复制
(defmethod get-name ((somebody person) .somebody.name)

或者,如果name本身就是一个类,

代码语言:javascript
复制
(defmethod get-name ((somebody person) .somebody.name.first-name)

其中一个限制是s-表达式不能在点之间工作,比如说。

代码语言:javascript
复制
.(get-my-class).name

不起作用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39183349

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档