1

我有另一个关于在 Common Lisp 中解码 JSON 的问题。我决定ST-JSON作为我的工具。我能够获取JSO包含 JSON 数据的对象,并使用st-json:getjso. 我想编写一个原则上类似的宏destructuring-bind,它将为以 JSON 字段命名的变量提供本地绑定(从那时起,我开始怀疑这是否是一个好主意,但这是一个不同的问题)。我想出了以下内容:

(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.在哪里的错误PARAMS。谁可以给我解释一下这个?

谢谢。

4

1 回答 1

5

显然,您使用的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")

或者,如果您愿意,可以使用“模板”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")

在这里,变量绑定来自第一个(模板)JSON,值来自第二个。模板 JSON 在宏扩展时解析,params每次执行代码时都会解析 JSON。

我不知道这两种方法对您是否有用。

于 2014-04-24T11:44:42.397 回答