我有这样的事情:
(def a "text")
(def b "text")
(def c nil)
(def d 8)
(def e "")
(def testlist (list a b c d e ))
现在,有没有办法获取变量名称的字符串?我假设没有'没有'是最可能的答案。
name似乎不起作用,因为它只返回值。列表是否仅包含def之后的值?
编辑:我忘记了这个问题可能是必不可少的:我既不能使用eval,也不能使用defmacro,两者都不允许(出于安全等原因)。所以,是的......答案 0 :(得分:1)
您将无法从变量名称中获取字符串,因为Clojure会尽快评估它们以生成testlist
=> (def testlist (a b c d e ))
("text" "text" nil 8 "")
但是,您可以quote the list检索与每个变量名称相关联的符号
=> (def testlist (quote (a b c d e ))) ;; equivalent to '(a b c d e ))
(a b c d e)
然后使用str
函数将这些符号转换为字符串
=> (map str testlist)
("a" "b" "c" "d" "e")
稍后,您可以eval
此列表来检索命名空间上下文中的值
=> (map eval testlist)
("text" "text" nil 8 "")
请注意,将eval
与外部输入(例如read-line
)一起使用可以创建a security risk in Clojure and other languages。
此外,必须在与其定义相同的命名空间中评估列表。否则,Clojure将无法解析符号。
=> (ns otherns)
=> (map eval user/testlist)
java.lang.RuntimeException: Unable to resolve symbol: a in this context
大多数情况下的最佳做法是使用macros
答案 1 :(得分:1)
你可以用宏来做这件事(只是为了好玩。我认为它根本不是一个可行的用例)。
user> (defmacro list+ [& syms]
`(with-meta (list ~@syms) {:vars (quote ~syms)}))
#'user/list+
user> (def testlist (list+ a b c d e))
#'user/testlist
user> (-> testlist meta :vars)
(a b c d e)
user> (defn nil-vals-names [data]
(for [[v name] (map vector data (-> data meta :vars))
:when (nil? v)]
name))
#'user/nil-vals-names
user> (nil-vals-names testlist)
(c)
答案 2 :(得分:0)
目前还不清楚你想要实现的目标,还有一种可能的方法。
meta
函数获取引用并返回带有:name
字段的映射,该字段包含变量名称的字符:
user=> (def foo 42)
#'user/foo
user=> (meta #'foo)
{:line 1, :column 1,
:file "/some/tmp/file.clj",
:name foo,
:ns #namespace[user]}