【问题标题】:Clojure: Name of variables in a listClojure:列表中变量的名称
【发布时间】:2017-12-14 11:44:29
【问题描述】:

我有这样的事情:

(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,两者都是不允许的(出于安全等原因)。所以,是的……

【问题讨论】:

  • 这是一个猜测:我不知道 clojure。但我怀疑你是按值创建列表,所以列表只包含值,而不是对变量的引用。
  • 您可以构造一个符号列表:(list 'a 'b 'c 'd 'e) 或 vars:(list #'a #'b #'c #'d #'e)
  • 您确实需要一个宏来执行此操作,而且通常当人们想要执行此操作时,原因并不是很有说服力,而且几乎总是不是一个好主意。
  • @Josh 原因是,我想检查 nil 和空,然后输出这些变量的名称。想法是我不知道这个列表中有多少元素,只是检查每个元素都会返回结果。
  • @Kris 是的,我可以,我只是在寻找一种不这样做的懒惰方法。

标签: clojure


【解决方案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】:

    您将无法从变量名中获取字符串,因为 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

    【讨论】:

      【解决方案3】:

      目前还不清楚你想达到什么目标,但仍有可能的方法。

      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]}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-31
        • 1970-01-01
        • 2014-06-14
        • 1970-01-01
        • 1970-01-01
        • 2020-01-16
        • 2016-06-24
        相关资源
        最近更新 更多