如何确定一个函数的参数数量在Clojure? [英] How can I determine number of arguments to a function in Clojure?
问题描述
在clojure中给出一个函数x如何以编程方式获取参数个数?
Given a function x in clojure how can I programatically get a count of the number of arguments?
例如:
(fn a [b c] ...) has has two arguments
(fn a [] ...) has has zero arguments
推荐答案
如果你可以访问保存函数的var,通过以下列方式访问其元数据:
If you have access to the var that holds the function you can get the argument count by accessing its metadata in the following way:
(defn arities [v]
(->> v meta :arglists (map count)))
(defn a [])
(defn b [_ _])
(map arities [#'a #'b])
;= ((0) (2))
arities
将返回一个seq和所有的函数的arity。这具有缺点,对于可变参数向量( [_ _& _]
),它将返回(4)。
arities
will return a seq with all the arities for the function. This has the disadvantage that for a variadic argument vector ([_ _ & _]
) it will return (4).
(defn c [_ _ & _])
(arities #'c)
;= (4)
这可以通过从所有参数列表中删除&
。
This could be fixed by removing the &
symbol from all the argument lists.
(defn arities [v]
(->> v
meta
:arglists
(map #(remove #{'&} %))
(map count)))
(arities #'c)
;= (3)
如果你没有访问var,下面是一个小功能我已经用来检测函数的参数计数。它使用反射,所以它不是你可能想要采取的,如果你需要良好的性能。还要考虑它依赖于实现的细节。
If you don't have access to the var, the following is a little function that I've used to detect the argument count of a function. It uses reflection so it's not the approach you might want to take if you need good performance. Also take into account that it relies on implementation details.
(defn n-args [f]
(-> f class .getDeclaredMethods first .getParameterTypes alength))
(defn a [])
(defn b [_ _])
(defn c [_ _ & _])
(map n-args [a b c])
;= (0 2 3)
EDIT
我意识到结果3的变量函数定义为(defn x [_ _& _] ,,,)
,实际上是相当误导,因为它是相同的结果,你会获取具有3个参数的函数。以下版本将为包含&
符号的参数向量返回:variadic
(除了 [&]
其中&
这是实际的参数名称)。如在 Jeremy Heiler 的注释中所提到的,从元数据获取参数计数只有在:arglists
的值未手动更改时才有效。 p>
After giving the answer another read, I realized the result 3 for a variadic function defined as (defn x [_ _ & _] ,,,)
, is actually quite misleading since it's the same result you would get for a function with 3 arguments. The following version will return :variadic
, instead of a specific number, for the argument vectors that contain the &
symbol (except for the case [&]
where &
it's the actual argument name). As mentioned in a comment by Jeremy Heiler getting the argument count from the metadata only works if the value for :arglists
is not manually changed.
(defn a [_])
(defn b [_ _])
(defn c [_ _ & _])
(defn d [_ _ _])
(defn e [&])
(defn variadic? [s]
(and (some #{'&} s)
(not (every? #{'&} s))))
(defn arities [v]
(->> v
meta
:arglists
(map #(if (variadic? %) :variadic %))
(map #(if (sequential? %) (count %) %))))
(map arities [#'a #'b #'c #'d #'e])
;= ((1) (2) (:variadic) (3) (:variadic))
更复杂,它依赖于更多的实现细节(即这是或那个函数声明吗?或函数是否扩展类X?),所以我不建议使用该方法。
The reflection version for this is a little more complicated and it relies on more implementation details (i.e. "Is this or that function declared?" or "Does the function extend the class X?"), so I wouldn't recommend using that approach.
这篇关于如何确定一个函数的参数数量在Clojure?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!