1. & varparam
相当于java中的可变参数, eg (defmacro defserverfn [name & body] ...), body表示其余的一个或者多个参数。
2. (list 1 2 3)
(1 2 3) 创建一个新列表。
3. unquote
`(1 2 ~(list 3 4)) => (1 2 (3 4)) 对表达进行evaluate操作。
4. unquote-splice
`(1 2 ~@(list 3 4)) => (1 2 3 4) 对表达式进行evaluate操作,去掉操作后的括号。
5. '(1 2 3)
quote,原文显示列表,不对列表进行evaluate操作。
6. #(operator %1 %2 %3 %4 %5)
(map #(+ % 3) [2 4 7]) ; -> (5 7 10) 创建匿名函数。
7. (map #(+ % 3) [2 4 7]) ; -> (5 7 10)
将函数一次应用于指定列表数据中的每一个数据,函数是源,数据是标的,类似java在一个数据集上使用迭代器循环操作。
8. (apply + [2 4 7]); -> 13
把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值,数据是源,函数是标的。
与map的区别就是map返回的还是一个集合,而apply返回的是一个元素, 可以把apply看作是SQL里面的聚合函数。
9. (let [a 1 b 2] (+ a b))
symbol binding. make a=1 and b=2 , then compute a+b, and finally print the result。
10. prefix#
在宏中使用,auto-gensym,在宏编译时产生唯一的symbol名字,防止命名冲突。
11. (doseq [x [1 2 3] y [1 2 3]] (prn (* x y)))
将参数x, y在各自指定的数据集上进行笛卡尔积混排后,按照指定函数进行运算,返回结果列表,类似java中的多重for循环。
12. (assoc {:key1 "old value1" :key2 "value2"} :key1 "value1" :key3 "value3") -> {:key3 "value3", :key2 "value2", :key1 "value1"}
将原始map中指定的key替换为指定的值,如果原始key不存在,则新增。
13. (defrecord Employee [name room])
定义数据类型Employee, 其中有两个字段,名称分别为name和room。
(def emp (Employee. "John Smith" 304))
实例化一个Employee对象。
(:name emp)
获取emp对象中的name字段值。
14. (str 1 2 3) -> "123"
字符串连接。
15. (defnk f [:b 10] (inc b))
和defn的区别在于可以为参数指定默认值,实际调用的时候如果不传参数,会使用默认值进行计算,否则采用传入的参数
(f) -> 11
(f :b 100) -> 101
16. (a/b)
调用命名空间a下的函数b.
17. (.. class-or-object (method1 args) (method2 args) (method3 args) )
串行连续调用多个函数,第一个函数的返回值作为第二个函数的第一个参数,以此类推。
18. 下划线(_)
经常在clojure代码的let语句块中看到下划线,例如:(let [a (expr_for_a) _ (println "log") b (expr_for_b)] (expr_body))
由于let中参数绑定均为k v 形式,在有些情况下,我们只在乎v表达式的执行,而不在乎返回值,此时k的位置需要用下划线"_"来占据,依次告知编译器,我们不在乎表达式的返回值。
19. for
作用和doseq类似,区别是可以使用额外的条件表达式进行笛卡尔积的筛选,支持的算子有:let :when :while,例如:
(for [x [0 1 2 3 4 5] :let [y (* x 3)] :when (even? y)] y) => (0 6 12)
将y设置为x*3,并且过滤掉奇数。
(for [x (range 3) y (range 3) :when (not= x y)] [x y]) => ([0 1] [0 2] [1 0] [1 2] [2 0] [2 1])
(for [x (range 3) y (range 3) :while (not= x y)] [x y]) => ([1 0] [2 0] [2 1])
将list x和y进行笛卡尔乘积,可以看到筛选算子when和while的区别在于while在list x中的每个元素第一次遇到不符合条件的list y中的元素时,list y后面的元素便全部忽略,从list x中的下一个元素开始重新对list y进行笛卡尔乘积。
20. 数据结构
‘(a b c) 链表
[a b c] 数组
#{a b c} set
{:a 1, :b 2, :c 3} map
21. assoc
应用于数据结构map, vector
(assoc {:key1 "old value1" :key2 "value2"} :key1 "value1" :key3 "value3") => {:key3 "value3", :key2 "value2", :key1 "value1"}
拷贝一个新map,同名的key则覆盖旧value,不同的key则追加。
22. (System/currentTimeMillis)
斜杠用于表示静态方法调用
23. (Integer. "100")
创建一个Integer对象,后面的参数是构造函数中所需参数。(注意Integer后面的点)
24. (-> 100 (Integer.) .toString)
向右的单箭头称为thread-first,按照从左到右的顺序依次将第一个form的计算结果作为第一个参数传入紧接下来右边的form. 将各个处理节点作为数据处理管道串联起来。
25. 在定义宏的时候可以看到三个特殊的语法糖 ` ~ ~@ #
例如:
(defmacro mymacro [number & body]
`(let [number# ~number]
(cond
(> number# 0) "positive"
(= number# 0) "zero"
:else ~@body)))
`称为syntax quote,表示宏主体里面的内容都会按照字面被展开,除了带波浪线的元素外,波浪线标注的元素number在展开时以其对应的值来代替,~@表示body是一个序列。number#是用来产生一个独特的符号名而不会和其他符号名冲突。
26. 获取map中指定key的值
(def simple_map {:a 1, :b 2, :c 3})
(:a simple_map)
27. type hint
(defn ^String substr [^String s ^Integer begin ^Integer end] (.substring s begin end))
使用^提示clojure编译器,方法的参数和返回值的类型。
28. #(get % key)
定义一个匿名函数,%表示函数的第一个参数(第2, 3个函数用%2, %3表示),该匿名函数获取参数中键值为key对应的value。
29. ((comp str + ) 1 2 3)
comp将多个函数按照right-to-left的顺序应用于指定数据集上,上述REPL运行结果为"6"。
30. (concat [1] [2] '(3 4) [5 6 7] #{9 10 8})
连接集合 (1 2 3 4 5 6 7 8 9 10)
31. (repeat 5 "x")
("x" "x" "x" "x" "x")
32. (iterate inc 5)
迭代计算 (5 6 7 8 9 10 11 12 13 14 15 ... n
如果不用take配合,最终会导致OOM。
33. (merge {:a 1 :b 2 :c 3} {:b 9 :d 4})
合并多个map,对于重复重现的Key,后面出现的会覆盖前面同样的Key。
34. (set '(1 1 2 3 2 4 5 5))
返回一个唯一集合 #{
1
2
3
4
5
}
35. (group-by f coll)
group-by根据算子f对集合coll进行排序,返回一个map,其中key为f计算的结果,key对应的value为coll中的对应元素,map按照key进行排序,
(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"]) -> {1 ["a"], 2 ["as" "aa"], 3 ["asd"], 4 ["asdf" "qwer"]}
36. (vals {:a "foo", :b "bar"})
返回map对应value的序列 ("foo" "bar")