本文主要对Clojure官网中的基础教程部分进行一下整理,对应地址https://clojure.org/guides/learn/syntax
函数
创建函数
定义一个函数,名称为 greet, 参数为name
1 2 3 4
| (defn greet [name] (str "Hello, " name))
(def greet (fn [name] (str "Hello, " name)))
|
使用
1 2
| user=> (greet "students") "Hello, students"
|
函数重载
1 2 3 4 5 6 7 8 9 10
| (defn messenger ([] (messenger "Hello world!")) ([msg] (println msg)))
user=> (messenger) Hello world!
user => (messenger "Hello class!") Hello class!
|
可变参数函数
1 2
| (defn hello [greeting & who] (println greeting who))
|
其中除第一个参数外,其余参数都会被放入 who 参数中,类型为list
1 2
| user=> (hello "Hello" "world" "class") Hello (world class)
|
匿名函数
1 2 3 4 5 6
| (fn [message] (println message))
((fn [message] (println message)) "Hello world!")
|
匿名函数可以使用更加简洁的写法
1 2 3 4 5 6 7 8
| #(+ 6 %)
#(+ %1 %2)
#(println %1 %2 %&)
|
应用函数
apply函数可以使用0个或多个参数调用函数
1 2 3 4
| (apply f '(1 2 3 4)) (apply f 1 '(2 3 4)) (apply f 1 2 '(3 4)) (apply f 1 2 3 '(4))
|
当入参是一个集合的时候,但是函数参数需要为单个参数时,apply很有用,如
1 2 3
|
(defn add [& z] (apply + z))
|
局部量
1 2 3 4
| (let [x 1 y 2] (+ x y))
|
闭包
1 2 3 4 5 6 7 8
| (defn messenger-builder [greeting] (fn [who] (println greeting who)))
(def hello-er (messenger-builder "Hello")) (hello-er "world!")
|
集合
vector
vector是一个有序的集合序列,使用 []
格式,如[1 2 3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| user=> (get ["abc" false 99] 0) "abc"
user=> (count [1 2 3 "a"]) 4
user=> (vector 1 2 3) [1 2 3]
user=> (conj [1 2 3] 4 5 6) [1 2 3 4 5 6]
|
list
list类似一个链表,与vector的区别是其会使用括号,如(1 2 3 4)
,在对list求值时,第一项会被解析成函数,后面的元素作为参数传递给它,如果不希望求值,可以在前面加上符号'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| user=> (+ 1 2 3) 6 user=> '(+ 1 2 3) (+ 1 2 3)
(def cards '(10 :ace :jack 9))
user=> (first cards) 10 user=> (rest cards) '(:ace :jack 9)
user=> (conj cards :queen) (:queen 10 :ace :jack 9)
user=> (def stack '(:a :b)) user=> (peek stack) :a user=> (pop stack) (:b)
|
set
set是一个无序不重复的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| (def players #{"Alice", "Bob", "kelly"})
user=> (conj players "Fred") #{"Alice" "Fred" "Bob" "Kelly"}
user=> (disj players "Bob" "Sal") #{"Alice" "Kelly"}
user=> (contains? players "Kelly") true
user=> (conj (sorted-set) "Bravo" "Charlie" "Sigma" "Alpha") #{"Alpha" "Bravo" "Charlie" "Sigma"}
user=> (def players #{"Alice" "Bob" "kelly"}) user=> (def new-players ["Tim" "Sue" "Grey"]) user=> (into player new-players) #{"Alice" "Greg" "Sue" "Bob" "Tim" "Kelly"}
|
map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| (def scores {"Fred" 1400 "Bob" 1240 "Angela" 1024})
user=> (assoc scores "Sally" 0) {"Angela" 1024, "Bob" 1240, "Fred" 1400, "Sally" 0}
user=> (dissoc scores "Bob") {"Angela" 1024, "Fred" 1400}
user=> (get scores "Angela") 1024
user=> (get scores "Sam" 0) 0
user=> (contains? scores "Fred") true user=> (find scores "Fred") ["Fred" 1400]
user=> (keys scores) ("Fred" "Bob" "Angela") user=> (vals scores) (1400 1240 1024)
user=> (def players #{"Alice" "Bob" "Kelly"}) user=> (zipmap players (repeat 0)) {"Kelly" 0, "Bob" 0, "Alice" 0}
user=> (def new-scores {"Angela" 300 "Jeff" 900}) user=> (merge scores new-scores) {"Fred" 1400, "Bob" 1240, "Jeff" 900, "Angela" 300}
user=> (def new-scores {"Fred" 500 "Angela" 900 "Sam" 1000}) user=> (merge-with + scores new-scores) {"Sam" 1000, "Fred" 1950, "Bob" 1240, "Angela" 1924}
user=> (def sm (sorted-map "Bravo" 204 "Alfa" 35 "Sigma" 99 "Charlie" 100)) user=> (keys sm) ("Afla" "Bravo" "Chalie" "Sigma")
|
应用对象
1 2 3 4 5
| (def person {:first-name "Kelly" :last-name "Keen" :age 32 :occupation "Programmer"})
|
获取属性
1 2 3 4 5 6 7 8 9
| user=> (get person :occupation) "Programmer" user=> (person :occupation) "Programmer" user=> (:occupation person) "Programmer"
user=> (:favorite-color person "beige") "beige"
|
更新属性
1 2
| user=> (assoc person :occupation "Baker")
|
删除属性
1
| user=> (dissoc person :age)
|
实体嵌套
1 2 3 4 5 6 7 8 9 10
| (def company {:name "WidgetCo" :address {:street "123 Main St" :city "Springfield" :state "IL"}})
user=> (get-in company [:address :city]) "Springfield" user=> (assoc-in company [:address :street] "303 Broadway")
|
使用Records替换map实现的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| (defrecord Person [first-name last-name age occupation])
(def kelly (->Person "Kelly" "Keen" 32 "Programmer"))
(def kelly (map->Person {:first-name "Kelly" :last-name "Keen" :age 32 :occupation "Programmer"}))
user=> (:occupation kelly) "Programmer"
|
流程控制
语句和表达式
在Java中,表达值返回值,语句没有返回值,但是在Clojure中一切都是表达式,都会返回值,多个表达式的情况下会返回最后一个值
流程控制表达式
if
1 2 3 4 5 6 7
| user=> (str "2 is " (if (even? 2) "even" "odd")) "2 is even"
user=> (if (true? false) "impossible!") nil
|
Truth
在Clojure中,所有的值都可以用来判断true或false, 只有值时false或者nil时结果时false,其余所有值进行逻辑判断时都是true
1 2 3 4 5 6 7 8 9 10 11 12
| user=> (if true :truthy :falsey) :truthy user=> (if (Object.) :truthy :falsey) :truthy user=> (if [] :truthy :falsey) :truthy user=> (if 0 :truthy :falsey) :truthy user=> (if false :truthy :falsey) :falsey user=> (if nil :truthy :falsey) :falsey
|
if and do
if语句中的then和else部分只能用来执行单个表达式,可以使用do
来创建执行多个语句
1 2 3 4 5
| (if (even? 5) (do (println "even") true) (do (println "odd") false))
|
when
when相当于简化版的if
, 但是它支持多个语句而不用使用do
1 2
| (when (neg? x) (throw (RuntimeException. (str "x must be positive: " x))))
|
cond
1 2 3 4
| (let [x 5] (cond (< x 2) "x is less than 2" (< x 10) "x is less than 10"))
|
cond and else
1 2 3 4 5
| (let [x 11] (cond (< x 2) "x is less than 2" (< x 10) "x is less than 10" :else "x is greater than or equal to 10"))
|
case
相比if
和cond
,使用其没有匹配到值时会抛出异常
1 2 3 4 5 6
| user=> (defn foo [x] (case x 5 "x is 5" 10 "x is 10")) user=> (foo 10) x is 10
|
case and else
1 2 3 4 5 6 7 8
| user=> (defn foo [x] (case x 5 "x is 5" 10 "x is 10" "x isn't 5 or 10"))
user=> (foo 11) x isn't 5 or 10
|
迭代
dotimes
执行n次表达值,返回nil
1 2 3 4 5
| user=> (dotimes [i 3] (println i)) 0 1 2
|
doseq
遍历序列
1 2 3 4 5
| user=> (doseq [n (range 3)] (println n)) 0 1 2
|
doseq与多个绑定值
1 2 3 4 5 6 7 8 9
| user=> (doseq [letter [:a :b] number (range 3)] (prn [letter number])) [:a 0] [:a 1] [:a 2] [:b 0] [:b 1] [:b 2]
|
for
生成序列,绑定方式同doseq
1 2 3 4
| user=> (for [letter [:a :b] number (range 3)] [letter number]) ([:a 0] [:a 1] [:a 2] [:b 0] [:b 1] [:b 2])
|
递归
loop 和 recur
1 2 3 4
| (loop [i 0] (if (< i 10) (recur (inc i)) i))
|
defn 与 recur
1 2 3 4
| (defn increase [i] (if (< i 10) (recur (inc i)) i))
|
异常
异常处理
1 2 3 4 5 6
| (try (/ 2 1) (catch ArithmeticException e "divide by zero") (finally (println "cleanup")))
|
抛出异常
1 2 3
| (try (throw (Exception. "something went wrong")) (catch Exception e (.getMessage e)))
|
异常与Clojure数据
1 2 3 4
| (try (throw (ex-info "There was a problem" {:detail 42})) (catch Exception e (prn (:detail (ex-data e)))))
|
命名空间
命名空间可以类似理解成Java中的包名
1 2 3 4 5
| (ns com.some-example.my-app "My app example" (:require [clojure.set :as set] [clojure.string :as str]))
|
加载java类时,使:import
1 2 3 4 5
| (ns com.some-example.my-app2 (:import [java.util Date UUID] [java.io File]))
|