(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