clojure编程初体验


使用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])

常用的一些函数的使用体会

  1. 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})
  1. 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)))
  1. conj
  2. seq
  3. when-let
  4. 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)
    
  5. 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
  1. reduce
  2. apply

函数间对比使用

  1. 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}))

评论
  目录