我跟随'Clojure in Action'并且我对此感到困惑:
(defn with-log [function-to-call log-statement ]
(fn [& args]
(println log-statement)
(apply function-to-call args)))
这是令我困惑的代码段。这是我到目前为止所能解读的内容:
(defn with-log [function-to-call log-statement] ..)定义一个名为“with-log”的函数,该函数接受参数'function-to-call'和'log-statement'和function -to-call是一个作为参数传递给该函数的函数。 下一节让我感到困惑:(fn [& args] ....是一个在这里定义的匿名函数吗?'with-log'函数是否返回一个新的函数定义?
(fn [& args]
(println log-statement)
(apply function-to-call args))
所以通过调用(with-log somefunc“my label”) - 它是否只是重新启动一个新的匿名函数?还是调用匿名函数?
答案 0 :(得分:6)
with-log
会生成一个函数,在调用时,它将完全执行function-to-call
所做的操作,但副作用是log-statement
将在*out*
之前打印到function-to-call
使用给匿名函数的参数来评估with-log
。
这是Decorator Pattern的示例 - 通过将现有函数的行为包装在另一个函数(即(fn ...)
使用with-log
表单创建的匿名函数)中来扩展现有函数的行为。
为了使装饰器函数function-to-call
与任何可以想象的(fn [& args] ...)
一起使用,指定了匿名函数的参数列表,以便可以使用function-to-call
使用多个参数调用它。当匿名函数调用apply
时,它使用函数with-log
“展开”参数列表。
使用((with-log some-fn "Calling some-fn") arg1 arg2)
的方式可能是:
(defn my-fn [a b]
(+ a b))
(def my-fn-with-logging (with-log my-fn "Calling my-fn"))
(my-fn 1 2) ; evaluates to 3
(my-fn-with-logging 1 2) ; prints "Calling my-fn" and evaluates to 3
或
{{1}}
答案 1 :(得分:1)
它返回匿名函数,并且没有被调用。
例如,这将调用具有给定参数的匿名函数:
((with-log some-fn "log statement") arg1 arg2)
这是有效的,因为返回的函数是列表中的第一项,这意味着它就像任何其他函数一样被调用。
答案 2 :(得分:0)
是的,你是对的。 (fn ..)
是一个创建匿名函数的表单。给定函数f
和一些值s
的这段代码将返回一个函数,该函数在被调用时将打印s
然后调用f
:
user=> (defn with-log [function-to-call log-statement ]
(fn [& args]
(println log-statement)
(apply function-to-call args)))
#'user/with-log
user=> (with-log + "String")
#<user$with_log$fn__1 user$with_log$fn__1@147264b1>
user=> ((with-log + "String") 1 2 3)
String
6
user=>
请注意以#<user$...
开头的行。这是刚刚创建的匿名函数的内部标识符,即对with-log
的简单调用返回一个函数。然后我们应用相同的函数(它的行为是相同的;事实上它将是不同的对象,因为每次调用with-log
都会为许多参数创建相同函数的新“实例”。打印"String"
字符串,然后REPL向我们显示(+ 1 2 3)
的结果。
Here您可以了解更多信息。