使用clojure开发web接口常见问题及解决方案
收藏的学习地址:
Leiningen中文教程
luminusweb官方文档
Clojure常用包
leiningen API
学习中命令行里敲过的
(+ 11 11 1111)
(/ 1 2)
(doc /)
(Take 5 (repeat 10))
(1 2 3) => error
'(1 2 3) => (1 2 3)
(doc if)
(def a-array [1 2 3])
(def b-array [1 2 3])
(idertical? a-array b-array)
(def a-list (1 2 3))
(def b-list [1 2 3])
(type a-list)
(type b-list)
(conj a-list 9)
(conj b-list 9)
(def my-add (fn [x y] (+ x y)))
(my-add 4 2)
`#{1 2 3}`
(type #{1 2 3})
(type {:a a})
(filter even? [1 2 3 ])
(map inc [1 2 3])
常用的一些函数的使用体会
- map
;;map 遍历list,格式化list里map的key对应的value
(require '[clj-time.format :as f])
=> nil
(def custom-formatter (f/formatter "yyyyMMdd"))
=> #'user/custom-formatter
(defn convert-format [d] (f/unparse custom-formatter (f/parse (f/formatter :date-hour-minute-second ) d)))
=> #'user/convert-format
(map (fn [m] (assoc m :create-time (convert-format (:create-time m))) )
[{:id 1
:create-time "2019-04-17T14:47:24"}
{
:id 2
:create-time "2019-04-17T14:47:44"}])
=> ({:id 1, :create-time "20190417"} {:id 2, :create-time "20190417"})
;;再写一个
```clojure
(map (fn [m] (assoc m
:office-name (format "%s-%s" (:office-id m) (:office-name m))))
[{
:office-id "1",
:office-name "耳鼻喉科",
:hospital-id "1",
:create-time "2019-04-17T14:47:24",
:deleted 0
},
{
:office-id "2",
:office-name "变态反应科",
:hospital-id "1",
:create-time "2019-04-17T14:47:44",
:deleted 0
}])
=>
({:office-id "1", :office-name "1-耳鼻喉科", :hospital-id "1", :create-time "2019-04-17T14:47:24", :deleted 0}
{:office-id "2", :office-name "2-变态反应科", :hospital-id "1", :create-time "2019-04-17T14:47:44", :deleted 0})
- date、timestamp、string
(import '[java.text SimpleDateFormat])
(import '[java.sql Timestamp])
;; timelong is the long int time seconds
(defn timestamp2date [timelong]
(.toString (Timestamp. timelong)))
;; date is date string 04/16/2012
(defn date2timestamp [date]
(.getTime (.parse (SimpleDateFormat. "MM/dd/yyyy") date)))
- conj
- seq
- when-let
- comp
就是对参数从右到左组合执行所有函数,如下面的函数:
可以转变为:((comp f1 f2 .. fn) arg1 arg2 .. argn)
举例(f1 (f2 (.. (fn arg1 arg2 .. argn))))
((comp str +) 8 8 8) ;;=> "24" (filter (comp not zero?) [0 1 0 2 0 3 0 4]) ;;=> (1 2 3 4) (map (comp - (partial + 3) (partial * 2)) [1 2 3 4]) ;;=> (-5 -7 -9 -11)
- partial
形如:((partial f arg1 arg2 .. argn) arga argb .. argz)
就是执行:
(f arg1 arg2 .. argn arga argb .. argz)
注意:偏函数的第一个参数是一个函数,后面至少有1个其他参数
partial函数称为“偏函数”或者“部分完整函数”,因为它是不完整的,定义也用def而不是defn。
user=> (def hundred-times (partial * 100))
#'user/hundred-times
user=> (hundred-times 5)
500
user=> (hundred-times 4 5 6)
12000
- reduce
- apply
函数间对比使用
- assoc vs update-in vs assoc-in
说法不一,详情参考Assoc-vs-Update/
assoc,只允许更新数据结构的第一层。处理数据的性能最高,几乎是assoc-in的两倍。
assoc-in 和update-in 可以使用路径表达式改变数据结构的内层。
如果新的值不依赖旧值,assoc-in就可以满足需求,不需要使用update-in;在有依赖关系时,使用update-in
(defrecord Person [fname lname address])
(defrecourd Address [street city state zip])
(def stu (Person. "Stu" "Halloway" (Address. "200 N Mangum" "Durham" "NC" 27707)))
(assoc stu :fname "Stuart")
(upate-in stu [:address :zip] inc)
有用的代码段
1、记录接口响应时间middleware
(defn record-response-time [handler]
(fn [req]
(let [start-date (System/currentTimeMillis)]
(handler req)
(let [res-time (- (System/currentTimeMillis) start-date)]
(println (format "%s took %d ms" (:uri req) res-time))))))
需要注意的是 record-response-time 需要放在 middleware 最外层,这样它才能纪录一个请求经过所有 middleware + handler 处理的时间。
2、移除map中值为nil的key
参考clojure nil? - Remove nil values from a map?
我使用的两个
(into {} (filter #(not (nil? (val %))) {:a true :b false :c nil}))
(into {} (remove #(nil? (val %)) {:a true :b false :c nil}))