【问题标题】:Access a structure instance by its name按名称访问结构实例
【发布时间】:2013-06-26 16:31:42
【问题描述】:

我正在尝试通过另一个结构实例或其名称访问结构实例的字段。诚然,这听起来很令人困惑,我有一个(非常结构化的)示例:

(defstruct author
  (name nil)
  (books '())
  (years '()))

(defstruct book
  (name nil)
  (author '())
  (copy-sold '()))

(defparameter hitchikers-guide
  (make-book :name "Hitchikers-Guide"
             :author '(douglas-adams)
             :copy-sold '(a lot)))

(defparameter douglas-adams
  (make-author :name "Douglas Adams"
               :books '(Hitchikers-guide restaurant life-and-universe fish)
               :years '(too few)))

(defparameter authors
  '(douglas-adams pterry))

我有实例hitchikers-guide。如果我想查找其作者的所有书籍,我可以输入 REPL (author-books douglas-adams),然后我会得到他所有书籍的列表。但是,如果我输入

(author-books (first (book-author hitchikers-guide)))

或

(author-books (first authors))

我收到错误消息:

值 DOUGLAS-ADAMS 不是预期的 AUTHOR 类型。

是我做错了,还是无法以这种方式访问​​这些字段?

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    您的变量authors 包含symbols,而不是authors。

    试试

    (defparameter authors (list douglas-adams pterry))
    

    改为(当然,如果 pterry 已经定义)。

    同样,(book-author hitchikers-guide) 是 symbols 的列表,而不是 authors。

    需要使用symbol-value获取对应的author。

    【讨论】:

    • 请注意 symbol-value 仅在这种情况下有效,因为变量被声明为特殊的,因为它们是用 defparameter 定义的。在这种情况下可以使用(defparameter authors (list douglas-adams pterry)),只是因为douglas-adams 和(可能)pterry 已经被定义。
    【解决方案2】:

    如果要通过符号作为标识符来查找对象,则需要为此使用数据结构。

    简单的版本是在包中使用符号。

    (defun find-object (name)
      (symbol-value name))
    
    (defun intern-object (object name)
      (setf (symbol-value name) object))
    

    但你也可以使用哈希表:

    (defvar *my-objects* (make-hash-table))
    
    (defun find-object (name)
      (gethash name *my-objects*))
    
    (defun intern-object (object name)
      (setf (gethash name *my-objects*) object))
    

    【讨论】:

    • 在稍旧但仍然合法的样式中,您还可以使用已知键将对象存储在符号的属性列表中。然后你可以用get 编写检索它,即(get 'douglas-adams 'author) 将为Douglas Adams 返回author 对象。
    • 讨论给定类型的 designators 也是一种很好的做法,尽管不是通用的。例如,string designator 是字符、字符串或符号,Common Lisp 中大多数与字符串相关的函数都接受字符串指示符,而不仅仅是字符串。您可以将 author designator 定义为作者或符号,并让与作者相关的函数采用 author designator(通过将符号静默映射到它命名的作者)。
    【解决方案3】:

    哪个先出现 - 作者还是书?

    ;; first the author
    (defstruct (author :conc-name make-author-internal)
      (name nil)
      (books '())
      (years '()))
    
    (defun make-author (name years)
      (make-author-internal :name name :books '() :years years))
    
    (defun author-add-book (author book)
      (setf (author-books author)
            (cons book (author-books author))))
    
    ;; now the book, requires an author (assumes one, if >1, use a list)
    (defstruct (book :conc-name make-book-internal)
      (name nil)
      (author nil)
      (copy-sold '()))
    
    (defun make-book (name author copy-sold)
      (let ((book (make-book-internal :name name :author author ...)))
        (author-add-book author book)
        book))
    
     ;; ...
    
     (defparameter douglas-adams
       (make-author "Douglas Adams" ...))
    
     (defparameter hitchikers-guide
       (make-book "Hitchikers-Guide" douglas-adams ...))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      • 2014-04-07
      相关资源
      最近更新 更多