2013-06-26 60 views
1

我試圖通過另一個結構實例或其名稱來訪問結構實例的字段。由於這聽起來固然很混亂,我有一個(非常構造)例如:通過其名稱訪問結構實例

(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))

我得到的錯誤信息:

價值道格拉斯亞當斯是預期類型的​​作者不是。

我做錯了嗎,還是沒有辦法以這種方式訪問​​這些字段?

回答

5

您的變量authors包含symbol s,而不是author s。

嘗試

(defparameter authors (list douglas-adams pterry)) 

代替(如,五言的,pterry已經被定義)。

同樣,(book-author hitchikers-guide)symbol s的列表,而不是author s。

您需要使用symbol-value才能獲得相應的author

+1

請注意'symbol-value'只適用於這種情況,因爲變量被聲明爲特殊的,因爲它們是用'defparameter'定義的。在這種情況下,做'(defparameter作者(列表道格拉斯 - 亞當斯pterry))'是可能的,只是因爲'douglas-adams'和(可能)'pterry'已經被定義。 –

4

如果你想通過一個符號來查找一個對象作爲它的標識符,你需要爲它使用一個數據結構。

簡單版本在包中使用符號。

(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)) 
+0

在稍舊但仍然合法的樣式中,您還可以使用已知密鑰將對象存儲在符號的屬性列表中。然後你可以用['get'](http://clhs.lisp.se/Body/f_get.htm)來檢索它,即'(get'douglas-adams'author)'會返回'author'對象道格拉斯亞當斯。 –

+1

這是一個不錯的做法,雖然不是通用的,但對於給定的類型討論_designators_。例如,_string指示符_是一個字符,字符串或符號,Common Lisp中與字符串相關的大部分函數都接受字符串指示符,而不僅僅是字符串。您可以將_作者指定符_定義爲作者或符號,並讓作者相關函數採用_作者指定符_(通過靜靜地將符號映射到它命名的作者)。 –

1
是先

- 作者或書嗎?

;; 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 ...))