我想创建一个接受必需参数x的函数,以及一个可选参数opt1或一个关键字参数opt2。
现在我有
(defn foo x & [opt1 {:keys [opt2]}]
...
但是上面的签名只允许我在x和opt1都存在时传递关键字参数opt2,如
(foo 'x 'opt1 {:opt2 'opt2})
不喜欢这个
(foo 'x {:opt2 'opt2})
请帮我创建一个带有必需参数X和opt1或opt2的函数,其中opt2是关键字参数。
谢谢。
编辑:我也希望对其他宏做同样的事情。所以我仍然需要使用defmacro。答案 0 :(得分:15)
问题是含糊不清。考虑一个函数(fn foo [x y & args])
,它接受两个可选参数,然后是任意数量的关键字参数。如果你那么称它为(foo :bar :baz)
,你的程序如何处理它? x
=> :bar
,y
=> :baz
?或x
和y
未提供,只有一个:bar
=> :baz
关键字参数?
即使在Common Lisp中,在解析函数参数方面可能比Clojure更具灵活性,但至少one popular book不建议混合使用可选参数和关键字参数。
最好的办法是将所有参数更改为位置参数,或将所有参数更改为关键字参数。如果使用关键字参数,则可以使用哈希映射解构来为“可选”关键字参数提供默认值。
user> (defn foo [& {:keys [x y bar]
:or {x 1 y 2 bar 3}}]
(prn [x y bar]))
#'user/foo
user> (foo)
[1 2 3]
nil
user> (foo :bar :baz)
[1 2 :baz]
nil
答案 1 :(得分:2)
你必须检查aditional参数是否是关键字参数(无论如何我假设你的或者是独家的),所以你可以这样做:
(defn foo [& args]
(if (= (count args) 1)
(let [[opt1] args] (println opt1))
(let [{:keys [opt2]} args] (println opt2))))
检查参数是否为关键字参数。由于您只有一个可选参数,因此很容易:检查是否只有一个作为关键字参数需要两个。