(seq coll)
根据给定的 coll
,返回一个相应的序列。
当 coll
为空时,返回 nil
。
(sql nil)
也返回 nil
。
seq
函数也可以作用于字符串、
(带有引用类型的)原生 Java 数组,
以及任何实现了 iterable
接口的对象。
; 处理空向量和 nil user=> (seq []) nil user=> (seq nil) nil ; 处理非空向量、列表、 Map 和字符串 user=> (seq [1 2 3]) (1 2 3) user=> (seq (list 1 2 3)) (1 2 3) user=> (seq {:language "clojure" :creator "Rich Hickey"}) ([:creator "Rich Hickey"] [:language "clojure"]) user=> (seq "hello world") (\h \e \l \l \o \space \w \o \r \l \d)
(rseq rev)
在常数时间内,返回 rev
的逆序序列。
rev
只能是向量或者 sorted-map 。
rev
为空时,返回 nil
。
; 空向量和空 sorted-map user=> (rseq []) nil user=> (rseq (sorted-map)) nil ; 非空向量 user=> (rseq [1 2 3]) (3 2 1) ; 非空 sorted-map user=> (def alpha (sorted-map :a "apple" :b "boy" :c "cat")) #'user/alpha user=> alpha {:a "apple", :b "boy", :c "cat"} user=> (rseq alpha) ([:c "cat"] [:b "boy"] [:a "apple"]) ; 一些不能处理的情况 user=> (rseq (list 1 2 3)) ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Reversible clojure.core/rseq (core.clj:1480) user=> (rseq nil) NullPointerException clojure.core/rseq (core.clj:1480)
过滤 sc
并返回一个序列,序列里的所有实体(entry)的键 ek
都必须符合条件 (true? (test (.. sc comparator (compare ek key)) 0))
。
如果没有任何实体符合条件,则返回 nil
。
参数 sc
必须是一个 sorted collection ,测试条件 test
可以是 <
、 <=
、 >
或者 >=
。
; 测试数据 user=> (def numbers (sorted-map 1 "one" 2 "two" 3 "three" 4 "four" 5 "five")) #'user/numbers user=> numbers {1 "one", 2 "two", 3 "three", 4 "four", 5 "five"} ; 过滤所有键小于 3 的键-值对 user=> (subseq numbers >= 3) ([3 "three"] [4 "four"] [5 "five"]) ; 过滤所有键小于 1 大于 4 的键-值对 user=> (subseq numbers >= 2 <= 4) ([2 "two"] [3 "three"] [4 "four"]) ; 过滤所有键小于 10 的键-值对,返回 nil user=> (subseq numbers >= 10) nil
用法和 subseq 一样,但是返回的序列是逆序排序的。
等同于执行 (rseq (subseq sc test key))
或者 (rseq (subseq sc start-test start-key end-test end-key))
。
; 测试数据 user=> (def numbers (sorted-map 1 "one" 2 "two" 3 "three" 4 "four" 5 "five")) #'user/numbers user=> numbers {1 "one", 2 "two", 3 "three", 4 "four", 5 "five"} ; 过滤所有键小于 1 大于 4 的键-值对,并逆序地返回结果 user=> (rsubseq numbers >= 2 <= 4) ([4 "four"] [3 "three"] [2 "two"]) ; 过滤所有键小于 2 的键-值对,并逆序地返回结果 user=> (rsubseq numbers > 2) ([5 "five"] [4 "four"] [3 "three"])
(vals map)
返回一个序列,序列里包含给定 map
的所有值(value)。
; 空 Map user=> (vals {}) nil ; 非空 Map user=> (vals {:python "Guido" :clojure "Rich" :ruby "Matz"}) ("Guido" "Matz" "Rich")
(keys map)
返回一个序列,序列里包含给定 map
的所有键(key)。
; 空 Map user=> (keys {}) nil ; 非空 Map user=> (keys {:python "Guido" :clojure "Rich" :ruby "Matz"}) (:python :ruby :clojure)
给定一个无参数的函数 f
(通常带有副作用),返回一个调用 f
函数 n
次的惰性序列。
如果不指定参数 n
,那么函数 f
可以执行无限次。
; 测试函数 user=> (defn greet [] "hi!") #'user/greet ; 定义一个执行 10 次 greet 的惰性序列 ; 并用 take 函数取出 5 个和 10 个 greet 的执行结果 user=> (def ten-greet (repeatedly 10 greet)) #'user/ten-greet user=> (take 5 ten-greet) ("hi!" "hi!" "hi!" "hi!" "hi!") user=> (take 10 ten-greet) ("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!") ; 试图取出 10086 个值,但 ten-greet 最多只返回 10 个值 ; 说明取出的数量最多只能和 n 一样大 user=> (take 10086 ten-greet) ("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!") ; 定义一个执行无限次 greet 的惰性序列 user=> (def infinite-greet (repeatedly greet)) #'user/infinite-greet user=> (take 10 infinite-greet) ("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!") user=> (take 100 infinite-greet) ("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!")
返回一个惰性序列,
序列元素的值为 x
、 (f x)
、 (f (f x))
、 (f (f (f x)))
,
诸如此类。
函数 f
必须是无副作用的。
; 生成一个计算所有正整数的惰性序列 user=> (def z (iterate inc 1)) #'user/z ; 取出第一个和第二个正整数 user=> (nth z 0) 1 user=> (nth z 1) 2 ; 取出前十个正整数 user=> (take 10 z) (1 2 3 4 5 6 7 8 9 10)
返回一个包含 n
个 x
的惰性序列。
如果不指定 n
,那么值 x
可以被包含无限次。
; 定义一个包含 10 个 "hi" 的惰性序列 user=> (def ten-hi (repeat 10 "hi")) #'user/ten-hi user=> ten-hi ("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi") ; 定义一个包含无限个 "hi" 的惰性序列 user=> (def infinite-hi (repeat "hi")) #'user/infinite-hi user=> (take 10 infinite-hi) ("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi") user=> (take 20 infinite-hi) ("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi")
返回一个惰性序列,
序列里包含从大于等于 start
到小于 end
区间内的所有数字(start <= numbers < end
),
数字的步进以 step
指定。
默认情况下, start
为 0
, step
为 1
,而 end
则为无限。
; 不指定任何参数,返回一个包含所有非负整数的惰性序列 ; 0, 1, 2, 3 ... user=> (take 3 (range)) (0 1 2) user=> (take 10 (range)) (0 1 2 3 4 5 6 7 8 9) ; 只指定 end ; 返回大于等于 0 到小于 end 之内的所有整数 user=> (range 5) (0 1 2 3 4) user=> (range 10) (0 1 2 3 4 5 6 7 8 9) ; 指定 start 和 end user=> (range 5 10) (5 6 7 8 9) user=> (range 0 10) (0 1 2 3 4 5 6 7 8 9) ; 指定 start 、 end 和 step ; 第一个惰性序列计算 2 到 20 内的所有偶数 ; 第二个惰性序列计算 1 到 20 内的所有奇数 user=> (range 2 20 2) (2 4 6 8 10 12 14 16 18) user=> (range 1 20 2) (1 3 5 7 9 11 13 15 17 19)
(keep f coll)
对于 coll
中的每个项 item
,
(keep f coll)
返回一个惰性序列,
序列包含 (f item)
除 nil
之外的所有计算结果。
因为带副作用的函数会返回与计算结果无关的虚假值,
因此,为了确保虚假值不会混进 keep
所生成的惰性序列中,
f
必须是一个无副作用的函数。
user=> (keep inc [1 2 3]) (2 3 4) ; 将空的 collection 传给 seq 函数会返回 nil ; 可以根据这个性质来测试 keep ; 看它是否真的会省略等于 nil 的值 user=> (seq []) nil user=> (keep seq (list [1 2 3] [] [4 5 6])) ((1 2 3) (4 5 6))
(distinct coll)
给定一个 coll
,返回一个无重复元素的惰性序列。
; 有重复元素的向量 user=> (distinct [1 2 1 2]) (1 2) ; 无重复元素的向量 user=> (distinct [1 2 3 4]) (1 2 3 4)
(filter pred coll)
返回一个惰性序列,
序列中包含 coll
里所有 (pred item)
测试结果为 true
的项。
pred
必须是一个无副作用的函数。
; 过滤 0 - 9 中所有的奇数 user=> (filter even? (range 10)) (0 2 4 6 8) ; 过滤 0 - 9 中所有的偶数 user=> (filter odd? (range 10)) (1 3 5 7 9) ; 过滤 0 - 9 中所有小于 10086 的数,结果为空 user=> (filter #(> % 10086) (range 10)) ()
(remove pred coll)
返回一个惰性序列,
序列中包含 coll
里所有 (pred item)
测试结果为 false
的项。
pred
必须是一个无副作用的函数。
; 删除 0 - 9 中的所有偶数 user=> (remove even? (range 10)) (1 3 5 7 9) ; 删除 0 - 9 中的所有奇数 user=> (remove odd? (range 10)) (0 2 4 6 8) ; 删除 0 - 9 中所有大于等于 0 的数字,结果为空 user=> (remove #(>= % 0) (range 10)) ()
(re-seq re s)
返回一个惰性序列,
序列里包含字符串 s
中所有匹配模式 re
的值,
匹配使用 java.util.regex.Matcher.find()
进行,
每个匹配值都经过 re-groups
处理。
; 查找字符串中的所有数字值 user=> (re-seq #"[0-9]+" "abs123def345ghi567") ("123" "345" "567")
(file-seq dir)
返回一个惰性序列,
序列包含给定目录 dir
的整个目录树
(包括目录中的文件和目录中的文件夹及文件夹里的文件)。
dir
必须是一个 java.io.File
对象。
; 引入 file 函数,它可以根据路径名创建一个 File 对象 ; 我们打开 /tmp 文件夹,并打印它的目录树 user=> (use '[clojure.java.io :only [file]]) nil user=> (def tmp-folder (file "/tmp")) #'user/tmp-folder user=> (file-seq tmp-folder) (#<File /tmp> #<File /tmp/.esd-1000> #<File /tmp/.esd-1000/socket> #<File /tmp/.Test-unix> #<File /tmp/mongodb-27017.sock> #<File /tmp/at-spi2> #<File /tmp/at-spi2/socket-1179-1131176229> #<File /tmp/at-spi2/socket-1268-1804289383> #<File /tmp/at-spi2/socket-1169-1369485920> #<File /tmp/mongodb-28017.sock> #<File /tmp/.X0-lock> #<File /tmp/.org.chromium.Chromium.NUsJHg> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonSocket> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonCookie> #<File /tmp/keyring-NwNaja> #<File /tmp/keyring-NwNaja/ssh> #<File /tmp/keyring-NwNaja/gpg> #<File /tmp/keyring-NwNaja/pkcs11> #<File /tmp/keyring-NwNaja/control> #<File /tmp/.ICE-unix> #<File /tmp/.ICE-unix/1303> #<File /tmp/cron.qpBNVU> #<File /tmp/pulse-PKdhtXMmr18n> #<File /tmp/ssh-ElvUhBgb1303> #<File /tmp/ssh-ElvUhBgb1303/agent.1303> #<File /tmp/.font-unix> #<File /tmp/pulse-397VI5uG1yhc> #<File /tmp/pulse-397VI5uG1yhc/pid> #<File /tmp/pulse-397VI5uG1yhc/native> #<File /tmp/pulse-397VI5uG1yhc/dbus-socket> #<File /tmp/hsperfdata_huangz> #<File /tmp/hsperfdata_huangz/9350> #<File /tmp/.X11-unix> #<File /tmp/.X11-unix/X0> #<File /tmp/.XIM-unix> #<File /tmp/.esd-120> #<File /tmp/pulse-T9RwKSB1FebW>) ; 使用 doseq 、 sort 和 println 函数 ; 打印一个更美观的、经过排序的目录树 user=> (doseq [f (sort (file-seq tmp))] (println f)) #<File /tmp> #<File /tmp/.ICE-unix> #<File /tmp/.ICE-unix/1303> #<File /tmp/.Test-unix> #<File /tmp/.X0-lock> #<File /tmp/.X11-unix> #<File /tmp/.X11-unix/X0> #<File /tmp/.XIM-unix> #<File /tmp/.esd-1000> #<File /tmp/.esd-1000/socket> #<File /tmp/.esd-120> #<File /tmp/.font-unix> #<File /tmp/.org.chromium.Chromium.NUsJHg> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonCookie> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonSocket> #<File /tmp/at-spi2> #<File /tmp/at-spi2/socket-1169-1369485920> #<File /tmp/at-spi2/socket-1179-1131176229> #<File /tmp/at-spi2/socket-1268-1804289383> #<File /tmp/cron.qpBNVU> #<File /tmp/hsperfdata_huangz> #<File /tmp/hsperfdata_huangz/9350> #<File /tmp/keyring-NwNaja> #<File /tmp/keyring-NwNaja/control> #<File /tmp/keyring-NwNaja/gpg> #<File /tmp/keyring-NwNaja/pkcs11> #<File /tmp/keyring-NwNaja/ssh> #<File /tmp/mongodb-27017.sock> #<File /tmp/mongodb-28017.sock> #<File /tmp/pulse-397VI5uG1yhc> #<File /tmp/pulse-397VI5uG1yhc/dbus-socket> #<File /tmp/pulse-397VI5uG1yhc/native> #<File /tmp/pulse-397VI5uG1yhc/pid> #<File /tmp/pulse-PKdhtXMmr18n> #<File /tmp/pulse-T9RwKSB1FebW> #<File /tmp/ssh-ElvUhBgb1303> #<File /tmp/ssh-ElvUhBgb1303/agent.1303> nil
(line-seq rdr)
返回一个惰性序列,
序列里包含从文件 rdr
中读出的所有字符串行。
rdr
必须是一个 java.io.BufferedReader
对象。
; 引入 reader 函数,它可以创建一个 java.io.BufferedReader 对象 ; 读出 animal.txt 文件中的所有内容,之后再将文件联接关闭 user=> (use '[clojure.java.io :only [reader]]) nil user=> (def animal (reader "animal.txt")) #'user/animal user=> (line-seq animal) ("dog" "cat" "monkey" "lion" "tiger" "dolphin") user=> (.close animal) nil ; 用 with-open 来自动处理文件的打开和关闭 ; 并用更美观的方式打印 animal.txt 文件的内容 user=> (with-open [animal (reader "animal.txt")] (let [all-animal (line-seq animal)] (doseq [a all-animal] (println a)))) dog cat monkey lion tiger dolphin nil
(tree-seq branch? children root)
返回一个惰性序列, 序列里包含通过深度优先遍历得出的一棵树中的所有节点。
branch?
函数接受一个参数,
通过向它传入一个节点,可以判断该节点是否拥有子节点。
children
函数接受一个参数,
通过向它传入一个节点,可以得到一个包含该节点的所有子节点的序列。
children
函数只会在那些
branch?
函数返回 true
的节点被调用。
root
是树的根节点。
; 函数 file-seq 用于列出一个文件夹的整个目录树 ; 它是展示 tree-seq 用法的一个极好的例子 (defn file-seq [dir] (tree-seq (fn [^java.io.File f] (. f (isDirectory))) ; 检查文件 f 是不是一个文件夹 (fn [^java.io.File d] (seq (. d (listFiles)))) ; 如果是的话,就用 listFiles 方法遍历它 dir)) ; 树的根节点是传入的文件夹
(xml-seq root)
返回一个惰性序列,序列里包含一棵 xml 元素树。
xml 文件可以用 clojure.xml/parse
函数解释。
; 解释一个 xml 文件,并提取内容 user=> (require 'clojure.xml) nil user=> (def content (clojure.xml/parse "http://www.w3schools.com/xml/note.xml")) #'user/content ; 根据 xml 内容,生成 xml 树 user=> (def tree (xml-seq content)) #'user/tree user=> tree ({:tag :note, :attrs nil, :content [{:tag :to, :attrs nil, :content ["Tove"]} {:tag :from, :attrs nil, :content ["Jani"]} {:tag :heading, :attrs nil, :content ["Reminder"]} {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]}]} {:tag :to, :attrs nil, :content ["Tove"]} "Tove" {:tag :from, :attrs nil, :content ["Jani"]} "Jani" {:tag :heading, :attrs nil, :content ["Reminder"]} "Reminder" {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]} "Don't forget me this weekend!") ; 遍历树 user=> (nth tree 0) {:tag :note, :attrs nil, :content [{:tag :to, :attrs nil, :content ["Tove"]} {:tag :from, :attrs nil, :content ["Jani"]} {:tag :heading, :attrs nil, :content ["Reminder"]} {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]}]} user=> (nth tree 1) {:tag :to, :attrs nil, :content ["Tove"]} user=> (nth tree 2) "Tove" user=> (nth tree 3) {:tag :from, :attrs nil, :content ["Jani"]} user=> (nth tree 4) "Jani"
(keep-indexed f coll)
对于 coll
中的每个项 item
,
以及 item
对应的索引下标 index
,
(keep-indexed f coll)
返回一个惰性序列,
序列中包含 (f index item)
除 nil
之外的所有计算结果。
因为带副作用的函数会返回与计算结果无关的虚假值,
因此,为了确保虚假值不会混进 keep-indexed
所生成的惰性序列中,
f
必须是一个无副作用的函数。
; 返回 0 - 9 内所有排序位置(index)为偶数的数字 user=> (keep-indexed #(if (even? %1) %2 nil) (range 10)) (0 2 4 6 8)
(cons x seq)
返回一个新的序列,
序列的第一个元素是 x
,
而 seq
则是序列的其余部分。
; cons 起数字 1 和空列表 user=> (cons 1 '()) (1) ; cons 起数字 1 和列表 (2 3) user=> (cons 1 (list 2 3)) (1 2 3)
conj
的完整词义是 conjoin ,
表示『相连接』的意思,
它用于将元素和 collection 拼接起来。
需要注意的是,
根据 coll
的类型,
组合会发生在 coll
的不同地方,
也即是, 元素 x
可能会被加入到 coll
的最左边,也可能会被加入到最右边。
当 coll
等于 nil
,
也即是,执行 (conj nil item)
时,
结果为 (item)
。
; coll 为 nil user=> (conj nil 1) (1) ; 向量的组合在尾部进行 user=> (conj [0 1 2] 3) [0 1 2 3] ; 列表的组合在头部进行 user=> (conj (list 0 1 2) 3) (3 0 1 2) ; 处理多个元素的 conj ; 注意向量和列表的结果之间的不同 user=> (conj [0 1 2] 3 4 5) [0 1 2 3 4 5] user=> (conj (list 0 1 2) 3 4 5) (5 4 3 0 1 2)
返回一个惰性序列,序列里包含所有传入 collection 的全部元素。
; 另个、一个或多个 collection 组合 user=> (concat) () user=> (concat [1]) (1) user=> (concat [1] [2]) (1 2) user=> (concat [1] [2] [3]) (1 2 3) user=> (concat [1] [2] [3] [4 5 6]) (1 2 3 4 5 6) ; 传入 concat 的参数必须都是 collection ; 组合元素和 collection 是 cons 和 conj 的任务 ; user=> (concat 1 [2 3]) ; IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:487)
(reverse coll)
逆序给定的 coll
。
这个操作不是惰性(lazy)的。
(user=>(reverse [1 2 3 4]) (4 3 2 1)
返回对 coll
进行排序之后得到的序列。
如果不指定 comparator
,
那么默认使用 compare.
,
comparator
必须实现 java.util.Comparator
。
user=> (sort [4 2 1 3]) (1 2 3 4) user=> (sort >= [4 2 1 3]) (4 3 2 1) user=> (sort <= [4 2 1 3]) (1 2 3 4)
(shuffle coll)
返回对 coll
进行乱序排列之后得出的序列。
user=> (shuffle [1 2 3 4]) [4 1 3 2] user=> (shuffle [1 2 3 4]) [1 3 2 4]
(count coll)
返回 coll
中元素的数量。
(count nil)
返回 0
。
coll
也可以是字符串、数组、Java Collection 和 Map 。
user=> (count nil) 0 user=> (count [1 2 3 4]) 4 user=> (count (list 1 2 3 4)) 4 user=> (count "string") 6 user=> (count {:clojure "Rich" :python "Guido" :ruby :Matz}) 3
(counted? coll)
如果 coll
实现了常数复杂度的 count
操作,那么返回 true
。
; 向量、列表、Map 和集合的 count 操作都是常数复杂度的 ; 但字符串不是 user=> (counted? [1 2 3]) true user=> (counted? '(1 2 3)) true user=> (counted? {:clojure "Rich"}) true user=> (counted? #{:a :b :c}) true user=> (counted? "string") false
(empty? coll)
如果 coll
中不包含任何元素,那么返回 true
,
效果等同于执行 (not (seq coll))
。
请使用惯用法 (seq x)
代替 (not (empty? x))
。
user=> (empty? '()) true user=> (empty? nil) true user=> (empty? [1 2 3]) false
(contains? coll key)
如果 key
存在于给定 coll
中,
那么返回 true
,否则返回 false
。
对于那些使用数值索引(index)的 collection 、比如向量和 Java 数组来说,
contains?
用于测试给定的数值 key
是否在索引的范围(range)之内。
contains?
不是线性复杂度的操作,
它可以在常数或对数复杂度内完成。
如果要检查一个 coll
是否符合某个条件,可以使用 some 。
user=> (contains? {:clojure "Rich"} :python) ; 测试 Map false user=> (contains? {:clojure "Rich"} :clojure) true user=> (contains? [1 3 5 7 9] 3) ; 测试向量 true user=> (contains? [1 3 5 7 9] 10086) false
(some pred coll)
返回 coll
中第一个满足条件 (pred x)
的值 x
。
如果 coll
中没有任何元素 x
能满足 (pred x)
,
返回 nil
。
将一个集合用作 pred
是 some
的一个惯用法:
比如说,
(some #{:fred} coll)
在 :fred
存在于 coll
时返回 :fred
,
如果不存在,就返回 nil
。
user=> (some #{:fred} [:fred :peter :jack]) :fred user=> (some #{:mary} [:fred :peter :jack]) nil user=> (some #(>= % 10) [1 3 5 7 9]) ; 查看是否有 >= 10 的值存在 nil user=> (some #(>= % 5) [1 3 5 7 9]) ; 查看是否有 >= 5 的值存在 true
(first coll)
返回 coll
中的第一个元素。
传入的 coll
会被 seq
函数处理。
如果 coll
为 nil
,返回 nil
。
user=> (first nil) nil user=> (first [1 2 3]) 1 user=> (first (list 1 2 3)) 1 user=> (first {:clojure "Rich" :python "Guido" :ruby "Matz"}) [:python "Guido"]
(next coll)
返回 coll
除了第一个元素之外,余下的其他全部元素。
传入的 coll
会被 seq
函数处理。
如果 coll
除了 (first coll)
之外,
没有其他别的元素,那么返回 nil
。
user=> (next nil) nil user=> (next [1]) nil user=> (next [1 2]) (2) user=> (next [1 2 3]) (2 3)
(import & import-symbols-or-lists)
import-list => (package-symbol class-name-symbols*)
对于 class-name-symbols
中的每个 name
来说,
将名字为 package.name
的类添加到当前 namespace 当中。
可以在 ns
宏中通过 :import
来调用这个函数。
user=> (import java.util.Date) ; 载入单个类 java.util.Date user=> (str (Date.)) "Wed Jun 20 23:18:42 CST 2012" user=> (import '(java.util Date Calendar) ; 载入多个类 '(java.net URI ServerSocket)) java.net.ServerSocket user=> (ns foo.bar ; 在 ns 宏中使用 (:import (java.util Date Calendar) (java.net URI ServerSocket))) java.net.ServerSocket
(cond & clauses)
接受一系列 test
/expression
对,
它每次对一个 test
进行求值,
如果某个 test
返回 true
,
那么 cond
求值并返回与这个 test
相对应的 expression
,
并且不再对其他 test
进行求值。
(cond)
返回 nil
。
user=> (defn type-of-number [n] (cond (> n 0) "positive number" (< n 0) "negative number" :else "zero")) #'user/type-of-number user=> (type-of-number 10) "positive number" user=> (type-of-number -5) "negative number" user=> (type-of-number 0) "zero"
定义一个(匿名)函数。
user=> (fn greeting [name] ; 创建匿名函数 (str "Hello, " name " .")) ;#<user$eval1$greeting__2 user$eval1$greeting__2@616fde> user=> ((fn greeting [name] ; 应用匿名函数 (str "hello, " name " .")) "moto") "hello, moto ." user=> ((fn greeting ; 参数重载(arity overloading) ([name] (greeting "Hello" name)) ([msg name] (str msg ", " name " ."))) "moto") "Hello, moto ." user=> ((fn greeting ; 接受不定数量参数的函数 [name & others] (if (seq others) (str "Hello, " name " and others: " others " .") (str "Hello, " name " ."))) "moto" "nokia" "apple") "Hello, moto and others: (\"nokia\" \"apple\") ."
使用一个函数体 body
,以及一个带有函数规格(specs)的向量 fnspecs
,
将向量里的名字和相应的函数进行绑定。
向量里的名字在函数定义中,还有函数体内,都是可见的。
user=> (letfn [(twice [x] (* x 2)) (six-times [y] (* 3 (twice y)))] (println "Twice 15 = " (twice 15)) (println "Six times 15 = " (six-times 15))) Twice 15 = 30 Six times 15 = 90 nil ;; 名字 twice 和 six-times 在离开 letfn 之后不可用 ;user=> (twice 15) ;CompilerException java.lang.RuntimeException: Unable to resolve symbol: twice in this context, compiling:(NO_SOURCE_PATH:7) ;user=> (six-times 15) ;CompilerException java.lang.RuntimeException: Unable to resolve symbol: six-times in this context, compiling:(NO_SOURCE_PATH:8)
partial
接受一个函数 f
,
以及少于正常 f
所接受参数数量的参数,
并返回一个匿名函数。
当这个匿名函数被调用时,
传给它的附加参数(additional args)会和之前给定的参数一起,
传给函数 f
。
user=> (def three-times (partial * 3)) #'user/three-times user=> (three-times 10) ; (* 3 10) 30 user=> (three-times 20) ; (* 3 20) 60 user=> (defn add-x-y-z [x y z] (+ x y z)) #'user/add-x-y-z user=> (def add-y-z (partial add-x-y-z 0)) ; x = 0 #'user/add-y-z user=> (def add-z (partial add-y-z 1)) ; y = 1 #'user/add-z user=> (add-z 2) ; z = 2 3 ; (+ 0 1 2)
comp
接受一系列函数作为输入,
返回一个匿名函数。
这个匿名函数接受可变数量的参数(variable number of args), 并按从右到左的顺序, 将传入的函数应用到参数中。
user=> ((comp str double +) 3 3 3) ; 以下两个表达等价 "9.0" user=> (str (double (+ 3 3 3))) "9.0"
(complement f)
接受一个函数 f
,返回一个匿名函数。
这个匿名函数接受的参数、产生的作用都和 f
一样,
但它返回的真值和 f
相反。
user=> (defn f [] (println "hello") false) #'user/f user=> (f) hello false user=> ((complement f)) hello true
(constantly x)
返回一个匿名函数,
接受任何数量的参数,
但总是返回 x
。
user=> (def ten (constantly 10)) #'user/ten user=> (ten) 10 user=> (ten 1) 10 user=> (ten 1 2) 10 user=> (ten 1 2 3) 10
assoc 表示 associate 的意思。
assoc
接受一个 Map ,还有一个或多个 key-val
对,
返回一个和传入 Map 类型相同的新 Map ,
除了原来传入 Map 已有的数据外,
新 Map 还包含传给 assoc
的那些 key-val
对。
当一个向量被应用到 assoc
函数时,
返回一个新向量,
新向量的索引下标(index) key
的值就是 val
。
注意索引下标必须 <= (count vector)
。
user=> (assoc {} :Clojure "Rich") {:Clojure "Rich"} user=> (assoc {:Clojure "Rich"} :Clojure "Rich Hickey") ; 如果有同名 key ,那么那么覆盖它 {:Clojure "Rich Hickey"} user=> (assoc [1 2 3] 0 10086) [10086 2 3] user=> (assoc [1 2 3] 3 10086) ; key 最大可以等于 (count vector) [1 2 3 10086] user=> (assoc [1 2 3] 10086 10086) ; key 不能大于 (count vector) IndexOutOfBoundsException clojure.lang.PersistentVector.assocN (PersistentVector.java:136)
dissoc 表示 dissociate 的意思。
dissoc
接受一个 Map ,以及任意个数的 key
,
返回一个和传入 Map 类型相同的新 Map ,
这个新 Map 不包含所有给定 key
的映射。
user=> (dissoc {:clojure "Rich" :python "Guido"}) ; 没有传入 key {:python "Guido", :clojure "Rich"} user=> (dissoc {:clojure "Rich" :python "Guido"} :python) ; 传入单个 key {:clojure "Rich"} user=> (dissoc {:clojure "Rich" :python "Guido"} :ruby) ; 传入一个不存在于 Map 的 key {:python "Guido", :clojure "Rich"} user=> (dissoc {:clojure "Rich" :python "Guido" :ruby "Matz"} :python :ruby) ; 传入多个 key {:clojure "Rich"}
(declare & names)
定义一些无绑定的 var 名字,用于提前声明(forward declarations)。
user=> (defn f [] (g)) ;CompilerException java.lang.RuntimeException: Unable to resolve symbol: g in this context, compiling:(NO_SOURCE_PATH:2) user=> (declare g) #'user/g user=> (defn f [] (g)) #'user/f