clojure实战——符号&@#’+-*/
本博客继续对clojure语言中一些符号进行讲解:&,@,-‘,#’。
保持“剩下的元素”——&、%&
&:保持”剩下的元素”
在解构中,可以用&符号保持解构剩下来的元素,有点像java中的可变参数
示例:
(comment
(defn &test
[a & rest]
rest)
(&test 1 2 3 4)
;; => '(2 3 4)
;; 剩下的元素被放入到rest中,rest是一个列表,而不是vector。
(let [[a & b] [1 2 3]]
b)
;; => (2 3)
(defn &test2
[a & [rest]]
rest)
(&test2 1 2 3 4)
;; => 2
;; 有趣的现象:剩下的元素为'(2 3 4),它被'[rest]解构,并将r绑定到第一个元素2
;; 类似于:(let [[r] '(2 3 4)] r) => 2
(defn &test3
[a & [r h a]]
(conj [] r h a))
(&test3 1 2 3 4)
;; => [2 3 4]
;; r、h、a 分别为2、3、4。
)
;; 在匿名函数中,可以用 %& 表示剩下的参数
;; %1, %2, ... %n 表示第n个参数
(#(apply + 5 %1 %2 %&) 100 200 300 400) ;; => 305
;; 上面的等价于:
(apply + 5 100 200 '(300 400))
解引用——@
@:解引用
@等同于deref函数
clojure中有很多实体都是可以解引用的,如delay、future、promise以及所有引用类型:atom、ref、agent、var。
示例:
(comment
(def atom-a (atom 10))
@atom-a
;; => 10
(def a-var 10)
@(var a-var)
;; => 10
)
获取符号指向的Var——#’
#’:用于获得一个符号(Sysmbol)所指向的Var。
clojure中,Var有def来创建
等同于var函数,返回值都是Var
clojure中,使用了两层”指针”来绑定”Sysmbol->Var->Function”
也就是说,我们通过一个符号来调用一个函数其实还经历了Var这一层:先找到符号指向的Var,再找到Var指向的函数。
这样做的好处是,我们可以动态地绑定Var指向某个具体的函数(有点多态的感觉)。
示例:
(comment
#'+
;; => #'clojure.core/+
(var +)
;; => #'clojure.core/+
;; 表明符号+指向的Var是#'clojure.core/+
;;查看#'和var的返回值类型
(class (var +))
(class #'+)
;; => clojure.lang.Var
;; 说明返回值类型是一个Var
;; 那#'clojure.core/+指向的函数是什么?可以对Var解引用
@#'+
;; => #object[clojure.core$_PLUS_ 0x77730aa7 "clojure.core$_PLUS_@77730aa7"]
;; 说明指向的函数是 #object[clojure.core$_PLUS_ 0x77730aa7 "clojure.core$_PLUS_@77730aa7"]
;; Var默认是静态的(static),不可被动态绑定
(def var-x 1)
(binding [var-x 1]
var-x)
;; => CompilerException java.lang.IllegalStateException: Can't dynamically bind non-dynamic var: clojure-async.symbols/var-x,
;; 在创建一个Var时,可以指定它是可动态绑定的。
;; 下面建立了一个可动态绑定的Var,并绑定一个根值为:default-value
(def ^:dynamic var-y :default-value)
(binding [var-y 2]
var-y)
;; => 2
;; 被动态绑定为2,但是它只作用于binding的作用域内。
var-y
;; => :default-value
)
减——-‘
-‘:加强版的减。
-‘函数可以接受一个参数,当只有一个参数时,默认被减数为0;当有多个参数时,和普通减号一样。
支持任意精度,不会像普通-那样出现越界异常。
示例:
(comment
(-' 3)
;; => -3 默认被减数为0
(-' 5 2 1)
;; => 2 和普通符号一样
(- 0 9000000000000000000 1000000000000000000)
;; => ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1521)
(-' 0 9000000000000000000 1000000000000000000)
;; => => -10000000000000000000N
)
加——+’
+’:加强版的+
接受0到N个数值的参数
支持任意精度
示例:
(comment
(+)
(+')
;; => 0
(+ 1 Long/MAX_VALUE)
;; => ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1521)
(+' 1 Long/MAX_VALUE)
;; => 9223372036854775808N
)
乘——*’
‘:加强版的
接受0到N个数值的参数
支持任意精度
示例:
(comment
(*)
(*')
;; => 1
(* 2 Long/MAX_VALUE)
;; => CompilerException java.lang.ArithmeticException: integer overflow, compiling
(*' 2 Long/MAX_VALUE)
;; => 18446744073709551614N
)