给出clojure中的函数x,我如何以编程方式获取参数数量的计数?
例如:
(fn a [b c] ...) has has two arguments
(fn a [] ...) has has zero arguments
答案 0 :(得分:13)
如果您有权访问保存该函数的var,您可以通过以下方式访问其元数据来获取参数计数:
(defn arities [v]
(->> v meta :arglists (map count)))
(defn a [])
(defn b [_ _])
(map arities [#'a #'b])
;= ((0) (2))
arities
将返回包含该函数所有arities的seq。这样做的缺点是,对于可变参数向量([_ _ & _]
),它将返回(4)。
(defn c [_ _ & _])
(arities #'c)
;= (4)
可以通过从所有参数列表中删除&
符号来解决此问题。
(defn arities [v]
(->> v
meta
:arglists
(map #(remove #{'&} %))
(map count)))
(arities #'c)
;= (3)
如果您无权访问var,以下是我用来检测函数参数计数的小函数。它使用反射,因此如果您需要良好的性能,这不是您可能想要的方法。还要考虑到它依赖于实现细节。
(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)
修改强>
在给出另一个回答之后,我意识到定义为(defn x [_ _ & _] ,,,)
的可变函数的结果3实际上是非常误导的,因为它与具有3个参数的函数的结果相同。对于包含:variadic
符号的参数向量,以下版本将返回&
而不是特定数字(案例[&]
除外,其中&
它是实际参数名称)。正如 Jeremy Heiler 的评论中所提到的,只有在:arglists
的值未被手动更改时才能从元数据中获取参数计数。
(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类?”)所以我不建议使用这种方法。
答案 1 :(得分:0)
你可以构造一个接受所有参数的函数,将它们放在一个列表中并像这样返回计数:
(defn arg-count [& rest] (count rest))
(arg-count) ;; 0
(arg-count 1 2 3) ;; 3