如何从一个plist获得一个属性

时间:2014-11-29 07:48:40

标签: lisp common-lisp string-to-symbol

我是Lisp的新手。 我想从属性列表中使用类似

的字符串变量访问特定属性
(setf sym (list :p1 1))
(setf x "p1")
(getf sym :x)

2 个答案:

答案 0 :(得分:4)

关于cl:getf

让Petit Prince回答是正确的getf可能是你想在这里使用的功能,但请注意,它不仅可以用于关键字符号。您可以将它用于任何对象。属性列表只是交替指标和值的列表,任何对象都可以作为指标:

(let ((plist (list 'a 'b 'c 'd)))
  (getf plist 'c))
;=> D

您甚至可以使用字符串作为指标:

(let* ((name "p1")
       (plist (list name 1)))
  (getf plist name))
;=> 1

但是,这可能不是很好的做法,因为 getf 会将指标与 eq 进行比较。这意味着使用字符串作为指标可能不可靠,具体取决于您的用例:

(let ((plist (list "p1" 1)))
  (getf plist "p1"))
;=> NIL

对于您的示例

在您的情况下,您尝试获取一个字符串并找到一个符号字符串相等的符号对象(即,具有相同的字符,但忽略大小写)。 循环对列表更有意义,并将指标与字符串相等进行比较。

(let ((plist '(:p1 1 :p2 2)))
  (loop 
     for (indicator value) on plist by #'cddr
     when (string-equal indicator "p1")
     return value))
;=> 1

当然,你可以将它包装在一个抽象函数中:

(defun getf-string-equal (plist indicator)
  (loop
     for (i v) on plist by #'cddr
     when (string-equal i indicator)
     return v))

(getf-string-equal '(:p1 1 :p2 2) "p1")
;=> 1

答案 1 :(得分:1)

getf的第二个参数是关键字,你有字符串。关键字是一个存在于KEYWORD包中的符号,通常由读者大写:

? (setf sym (list :p1 1))
(:P1 1)
? sym
(:P1 1)

所以你需要使用:

? (getf sym (find-symbol (string-upcase x) "KEYWORD"))
1