我还有一个关于在 Common Lisp 中解码 JSON 的问题。我选择了 ST-JSON
作为我的工具。我能够获取包含 JSON 数据的 JSO
对象,并使用 st-json:getjso
访问所有字段。我想写一个原则上类似于 destructuring-bind
的宏,它将为以 JSON 字段命名的变量提供本地绑定(bind)(从那时起我开始怀疑这是否是个好主意,但这是一个不同的问题) .我想出了以下内容:
(defmacro destructure-jso (jso &body body)
(let (keys values)
(st-json:mapjso #'(lambda (key value)
(push key keys)
(push value values))
jso)
`(destructuring-bind ,keys ,values
,@body)))
但是当我尝试在 JSO
对象上使用它时,出现错误 The value PARAMS is not of the expected type STRUCTURE.
where PARAMS
是对象。谁可以给我解释一下这个?
谢谢。
最佳答案
显然,您正在像这样使用 destructure-jso
:
(let ((params (st-json:read-json-from-string "{\"foo\":42,\"bar\":\"baz\"}")))
(destructure-jso params
(list foo bar)))
但是,destructure-jso
作为一个宏,在宏扩展时得到处理,甚至在 JSON 被解析之前。 params
作为符号传递给您的宏,没有被评估;即使尝试对其进行评估,它也将不受约束。
所以,如果你想写一个destructure-jso
,你将需要宏扩展时的键列表。您可以以正常方式传递列表:
> (defmacro destructure-jso-2 (vars json &body body)
`(let ,(mapcar #'(lambda (var)
(list var `(getjso ,(string-downcase (symbol-name var)) ,json)))
vars)
,@body))
DESTRUCTURE-JSO-2
> (let ((params (st-json:read-json-from-string "{\"foo\":42,\"bar\":\"baz\"}")))
(destructure-jso-2 (foo bar)
params
(list foo bar)))
(42 "baz")
或者,如果您愿意,可以使用"template"JSON 来创建映射:
> (defmacro destructure-jso-3 (template json &body body)
(let (bindings)
(st-json:mapjso #'(lambda (key val)
(declare (ignore val))
(push (list (intern (string-upcase key)) `(getjso ,key ,json))
bindings))
(st-json:read-json-from-string template))
`(let ,bindings
,@body)))
DESTRUCTURE-JSO-3
> (let ((params (st-json:read-json-from-string "{\"foo\":42,\"bar\":\"baz\"}")))
(destructure-jso-3 "{\"foo\":null,\"bar\":null}"
params
(list foo bar)))
(42 "baz")
在这里,变量绑定(bind)来自第一个(模板)JSON,值来自第二个。模板 JSON 在宏扩展时解析,params
JSON 每次执行您的代码时。
我不知道这两种方法是否对您有用。
关于json - ST-JSON JSO 对象的解构宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23266924/