Clojure语言学习笔记(二)

这篇博客详细介绍了Clojure中的特殊形式,包括quote、do、def和let,并重点讨论了let的解构特性,如顺序解构和map解构,展示了如何高效地从集合和映射中提取值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特殊形式

阻止求值:quote

quote阻止Clojure表达式求值,例如:

(quote x)
;=x
(symbol? (quote x))
;=true

quote对应的reader语法为单引号(’),reader在求值到单引号后会把它解析为一个quote:

'x
;=x

任何Clojure形式都可以被quote,包括数据结构,例如:

'(+ x x)
;=(+ x x)
(list? '(+ x x))
;=true
代码块:do

do会依次求值你传进来的所有表达式,并且把最后一个表达式的结果作为返回值,例如:

(do
    (println "hi")
    (apply * [4 5 6]))

; hi
;=120
定义Var:def

def的作用是在当前命名空间里定义(或重定义)一个var(可以赋值也可以不赋值):

(def p "foo")
p
;="foo"
本地绑定:let

let定义本地绑定,以下面例子为例,在Java中:

public static double hypot (double x, double y){
    final double x2 = x * x;
    final double y2 = y * y;
    return Math.sqrt (x2 + y2);
}

在Clojure中与之等价的是:

(defn hypot
    [x y]
    (let [x2 (* x y)
          y2 (* y y)]
    (Math/sqrt (+ x2 y2))))

上面的x2和y2在Java方法和Clojure函数里面的作用是一样的:给一个中间变量/值命名。
let定义的绑定有两个显著的特点:

  1. 所有本地绑定都是不可变的。可以在一个嵌套的let形式里面把一个本地绑定绑定到另外一个值,或者可以在一个绑定数组的后面把它绑定到别的值,但是没有办法改变一个let绑定的值。
  2. let的绑定数组在编译期可以对通用集合类型进行解构,利用”解构”,可以大大简化从绑定数组中抽取想要的数据的操作。
解构(let,第2部分)

Clojure访问一个集合中的多个数值的方法,以下面为例:
定义一个vector:

(def v [42 "foo" 99.2 [5 12]])

访问vector中元素的方法:

(first v)
;=42
(second v)
;="foo"
(last v)
;=[5 12]
(nth v 2)
;=99.2
(v 2)
;=99,2
(.get v 2)
;=99.2
  • Clojure提供了简单的函数访问顺序集合的第一个,第二个以及最后一个值。
  • 同时还提供了 nth 函数来返回顺序集合的指定下标的元素。
  • Clojure 里面的 vector 本身也是函数,它接收数组下标作为参数,返回该下标中保存的元素。
  • 所有的 Clojure 的顺序集合都实现了 java.util.List 这个接口,所以还可以使用List接口的 .get 方法来返回顺序集合中的元素。

let 支持两种类型的解构,对于顺序集合的解构以及对于 map 的解构。

顺序解构

顺序解构可以对任何顺序集合进行解构,包括:

  • Clojure原生的list、vector以及seq。
  • 任何实现了java.util.List 接口的集合(比如 ArrayList 和 LinkedList)。
  • Java 数组。
  • 字符串,对它解构的结果是一个个字符。

下面是一个基本的例子,解构上面的那个v:

最基本的顺序结构:
(def v [42 "foo" 99.2 [5 12]])

(let [[x y z] v]
    (+ x z))
;=141.2

解构的形式还支持嵌套解构形式,如下:

(let [[x _ _ [y z]] v]
    (+ x y z))
;=59

把解构形式和要被解构的集合摆在一起,如下所示:

[x  _     _    [y z ]]
[42 "foo" 99.2 [5 12]]

顺序解构的两个特性:

保持 “剩下的” 元素

可以使用 & 符号来保持解构剩下的那些元素:

 (let [[x & rest] v]
     rest)
 ;=("foo" 99.2 [5 12])
保持被解构的值

可以在解构形式中指定 :as 选项来把被解构的原始集合绑定到一个本地绑定:

 (let [[x _ z :as original-vector] v]
     (conj original-vector (+ x z)))
 ;=[42 "foo" 99.2 [5 12] 141.2]

这里 original-vector 被绑定到未做修改的集合 v 。如果要解构的集合是一个函数 调用的返回值,同时又想保持对于这个集合的绑定,那么这个特性会很方便。

map 解构

map 解构和顺序解构在概念上是一样的: 通过解构形式从 map 中抽出一些元素。map 解构对下面几种数据结构有效。

  • Clojure 原生的 hash-map、array-map,以及记录类型。
  • 任何实现了 java.util.Map 的对象
  • get 方法所支持的任何对象。如:
    — Clojure 原生 vector
    — 字符串
    — 数组
    最简单的map解构:
(def m {:a 5 :b 6
        :c [7 8 9]
        :d {:e 10 :f 11}
        "foo" 88
        42 false})
(let [{a :a b :b} m]
    (+ a b))
;=11

map 解构中用做 key 的不止是关键字,可以是任何类型的值:

(let [{f "foo"} m]
    (+ f 12))
;=100
(let [{v 42} m]
    (if v 1 0))
;=0

如果 map 解构的 vector 、字符串或者数组,那么解构的 key 是数字类型的数组下标。如:

(let [{x 3 y 8} [12 0 0 -18 44 6 0 0 1]]
    (+ x y))
;= -17

角标从 0 开始。
map 解构也可以处理内嵌 map:

(let [{{e :e} :d} m]
    (* 2 e))
;=20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值