【发布时间】:2013-11-24 14:05:21
【问题描述】:
(defrecord Sample (x y))
(def check (Sample. 1 2))
(:x check) ;returns 1
如果我收到 (:x check) 作为函数的参数,有没有办法访问检查?或者,换句话说,返回
#:user.Sample{:x 1, :y 2}
【问题讨论】:
(defrecord Sample (x y))
(def check (Sample. 1 2))
(:x check) ;returns 1
如果我收到 (:x check) 作为函数的参数,有没有办法访问检查?或者,换句话说,返回
#:user.Sample{:x 1, :y 2}
【问题讨论】:
不,如果将函数 (:x check) 作为参数传递,那么该值在进入函数之前已经被评估,你只会收到一个 1 作为值,你不能检索它来自的记录。
如果你需要函数内部的记录,为什么不传递check作为参数呢?
【讨论】:
'(:x check),那将只是函数内部的符号列表,无法“回溯”check 是调用函数之前的记录这一事实
check 是Var,您可以使用resolve/deref 来获得它的值 - (deref (resolve 'check)) => #user.Sample{:x 1, :y 2}。我在下面的答案中包含了更多信息。
正如Óscar 所述,(:x check) 不起作用,因为它的结果是1,而'(:x check) 不起作用,因为它的结果是一个包含关键字:x 和符号check 的列表。
但是,您可以使用 list 函数来代替引号:
(defn receiver [arg]
(map class arg))
;; With a quoted list it receives the symbol `check` rather
;; than the Sample record
(receiver '(:x check))
;=> (clojure.lang.Keyword clojure.lang.Symbol)
;; But this way it does receive the Sample
(receiver (list :x check))
;=> (clojure.lang.Keyword user.Sample)
并且可以评估(list :x check):
(eval (list :x check))
;=> 1
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval arg)))
(receiver (list :x check))
;=> "received (:x #user.Sample{:x 1, :y 2}); eval'd to: 1"
quote 和 list 行为如此不同的原因是 quote 没有评估它的论点。而且,当一个列表被引用时,这种效果是递归的:列表中的任何项目都不会被评估。
还有另一种类型的引用,称为语法引用或反引号(在 Clojure.org 页面上描述了 reader),它允许您选择性地取消引用(即评估)项目。
(require '[clojure.pprint])
(let [n 1
x :x
c check]
(clojure.pprint/pprint
(vector `(n x c)
`(~n x c)
`(~n ~x c)
`(~n ~x ~c))))
打印:
[(user/n user/x user/c)
(1 user/x user/c)
(1 :x user/c)
(1 :x {:x 1, :y 2})]
而且,实际上,我撒了一点谎。在这种特殊情况下,您实际上可以使用'(:x check)。 resolve 将返回与符号关联的 Var,deref(或其@ 读取器宏)将为您获取 Var 的值。
(resolve 'check)
;=> #'user/check
(deref (resolve 'check))
;=> #user.Sample{:x 1, :y 2}
(defn resolve-and-deref-symbols [form]
(map (fn [x] (if (symbol? x)
@(resolve x)
x))
form))
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval (resolve-and-deref-symbols arg))))
(receiver '(:x check))
;=> "received (:x check); eval'd to: 1"
我没有直接提到它,因为虽然它在这个例子中很容易工作,但它根本不适合一般情况。 (例如,它不适用于本地,处理命名空间和嵌套数据结构会很痛苦)。
【讨论】: