我写了一个宏来在一些有用的日志记录中包装一个函数定义:
(defmacro defn-logged
"Wraps functions in logging of input and output"
[fn-name args & body]
`(defn ~fn-name ~args
(log/info '~fn-name "input:" ~@args)
(let [return# (do ~@body)]
(log/info '~fn-name "output:" return#)
return#)))
Run Code Online (Sandbox Code Playgroud)
这对于没有文档字符串的函数非常有用:
(defn-logged foo
[x]
(* 2 x))
(foo 3)
; INFO - foo input: 3
; INFO - foo output: 6
; 6
Run Code Online (Sandbox Code Playgroud)
但是如果对于带有 docstrings 的函数非常失败:
(defn-logged bar
"bar doubles its input"
[x]
(* 2 x))
; IllegalArgumentException Parameter declaration clojure.tools.logging/info should be a vector
Run Code Online (Sandbox Code Playgroud)
如何让我的宏适用于有和没有文档字符串的函数?
一种方法是查看传递给 的参数defn-logged。如果名称后的第一个是字符串,则将其用作 doc 字符串,否则将 doc 留空:
(defmacro defn-logged
"Wraps functions in logging of input and output"
[fn-name & stuff]
(let [has-doc (string? (first stuff))
doc-string (if has-doc (first stuff))
[args & body] (if has-doc (rest stuff) stuff)]
`(defn ~fn-name {:doc ~doc-string} ~args
(println '~fn-name "input:" ~@args)
(let [return# (do ~@body)]
(println '~fn-name "output:" return#)
return#))))
Run Code Online (Sandbox Code Playgroud)
用文档字符串测试:
(defn-logged my-plus "My plus documented" [x y] (+ x y))
(doc my-plus)
; -------------------------
; user/my-plus
; ([x y])
; My plus documented
; nil
(my-plus 2 3)
; my-plus input: 2 3
; my-plus output: 5
; 5
Run Code Online (Sandbox Code Playgroud)
没有文档字符串的测试:
(defn-logged my-mult [x y] (* x y))
(doc my-mult)
; -------------------------
; user/my-mult
; ([x y])
; nil
; nil
(my-plus 2 3)
; my-mult input: 2 3
; my-mult output: 6
; 6
Run Code Online (Sandbox Code Playgroud)
它仍然不是完全等效的defn,至少因为defn支持在 map、reader 宏和 string 中传递的元数据。但它适用于文档字符串。
| 归档时间: |
|
| 查看次数: |
698 次 |
| 最近记录: |