我发现以下是一个坏主意,原因很多.我也意识到,鉴于我有一个23的stackoverflow代表,它的本质是假设我是一个新手学习编程.但是,请幽默我,并专注于"我们怎么做",而不是"你为什么要这样做/你不想这样做"的方面.
我想要的是:
(def dog (Dog. ...))
(def cat (Cat. ...))
(with-animal dog
(println (str "Dog: " (speak) "\n")))
(with-animal cat
(println (str "Cat: " (speak) "\n")))
Run Code Online (Sandbox Code Playgroud)
输出:
Dog: woof
Cat: meow
Run Code Online (Sandbox Code Playgroud)
所以基本上,我希望with-animal是一个宏,所有出现的"speak"函数调用都会被映射到我正在调用块的对象.
特别是,我不想写:
(let-binding [speak (fn [] "woof")] ...)
(let-binding [speak (fn [] "meow")] ...)
Run Code Online (Sandbox Code Playgroud)
相反,我希望with-animal将speak函数映射到我正在调用的对象的某个方法.
在Clojure中有一个干净的方法吗?
谢谢!
Art*_*ldt 20
动态绑定存在是有原因的,并且它有很多很好的用途,所以不用担心因为试图理解它而受到抨击:-)在许多旧的Clojure教程中存在一些混淆,这些教程早于添加^:动态元数据的需要对你期望动态重新绑定的变种.
第一个示例通过重新绑定现有名称来使用动态绑定.这消除了宏引入新符号的需要:
(def dog {:sound #(str "wooooof")})
(def cat {:sound #(str "mewwww")})
Run Code Online (Sandbox Code Playgroud)
定义我们将重新绑定为动态的函数(允许重新绑定)
(defn :^dynamic speak [] (println "eh?"))
Run Code Online (Sandbox Code Playgroud)
写一个基本模板宏来绑定说话动物中的函数:
(defmacro with-animal [animal & body]
`(binding [speak (:sound ~animal)]
~@body))
Run Code Online (Sandbox Code Playgroud)
并测试它:
(with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
Run Code Online (Sandbox Code Playgroud)
speak使用let 将符号引入范围,而无需动态绑定.这并不是说绑定在某种程度上是坏的,它更符合你不写的愿望(let-binding [speak (fn [] "meow")] ...)这种类型的maco被称为照应(如果你是这样的花哨的名字):
重要的部分是~'在speak符号之前明确地将不合格的符号引入范围:
user> (defmacro with-animal [animal & body]
`(let [~'speak (:sound ~animal)]
~@body))
#'user/with-animal
user> (with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
nil
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2804 次 |
| 最近记录: |