问题出现在我练习an Observer topic in a tutorial时我试图将该功能应用于用户但不能使用用户的数据字段,如姓名,姓氏。
假设用户可能有不同数量的数据字段,因此我们必须使用& args
参数。我的代码不起作用:
(ns observer.core)
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})
(apply
(fn [& args] (println (str "I am " (:name args) " " (:surname args) ".")))
user)
(apply
(fn [& args] (println (str "My sister is " (:name args) " " (:surname args) ".")))
user2)
输出:
I am .
My sister is .
observer.core>
如何修复它必须使用apply
函数?
apply
将地图转换为seq,即{:name "Alan" :surname "Smith" :alias "Mike"}
变为([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
您可以将其放回地图中,如果这是您需要的:
(let [user {:name "Alan" :surname "Smith" :alias "Mike"}]
(apply
(fn [& args]
(let [args (into {} args)]
(println (str "I am " (:name args) " " (:surname args) "."))))
user))
但对我来说这看起来有点紧张。我相信如果我知道如何使用这个功能,解决方案可能会更好。
通常有两种类型的函数:(fn :text "some" :row 25)
和(fn {:text "some" :row 25})
。
本着学习的精神:
看看Clojure - Cheatsheet。与Clojure合作10年,我仍然每天使用它。
(apply some-func (list x y z))
成为(some-func x y z)
,因为apply
假设第二个参数是一个列表(然后它解包)。
而您目前正在做的是将所有参数收集回名为args
的列表中
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [& args]
(prn 'ARGS args) ;; lets see what is actually in args
(println (str "I am " (:name args) " " (:surname args) ".")))
user)
;; -> ARGS ([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
;; -> I am .
输出就像@akond所说的那样。
当然,您可以将'用户'放在向量(或列表)中,但是不要使用'&'将所有内容收集回列表中(然后您必须再次选择内容):
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [args]
(prn 'ARGS args)
(println (str "I am " (:name args) " " (:surname args) ".")))
[user])
那会给你你想要的输出。但这或许有点奇怪,但如果你必须使用apply
并且你可以控制参数的“列表”部分,那肯定是可行的。
所以,@ akond的解决方案简单而干净。 并用Clojure "destructing"增加它:
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [& args]
(let [{:keys [name surname alias]} (into {} args)]
(println (str "I am " name " " surname "." (when alias (str " But call me " alias "!"))))))
user)
我相信你打算做这样的事情:
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})
(defn fn-1
[item]
(println (str "I am " (:name item) " " (:surname item) ".")) )
(defn fn-2
[item]
(println (str "My sister is " (:name item) " " (:surname item) ".")))
(fn-1 user)
(fn-2 user2)
结果:
I am Alan Smith.
My sister is Jane Smith.
必须通过列表包装用户对象或地图。
(ns observer.core)
(defrecord Person [name balance])
(def user (Person. "Alan" 150.34))
(def user2 {:name "Adam" :balance 629.74})
(def observers (atom #{}))
(swap! observers conj (fn [l] (println (str "2. " (:name l)))))
(swap! observers conj (fn [l] (println (str "1. " (:balance l)))))
(println "user")
(vec (map #(apply % (list user)) @observers))
(println "\nuser2")
(vec (map #(apply % (list user2)) @observers))
产量
user
1. 150.34
2. Alan
user2
1. 629.74
2. Adam
observer.core>