条件表达式 #

一、条件表达式简介 #

Clojure中的条件表达式都是表达式而非语句,它们都有返回值。Clojure提供了多种条件表达式来处理不同的分支场景。

1.1 真值判断 #

在Clojure中,只有 falsenil 是逻辑假:

clojure
(boolean true)

(boolean false)

(boolean nil)

(boolean 0)

(boolean "")

(boolean [])

二、if表达式 #

2.1 基本语法 #

clojure
(if condition
  then-expr
  else-expr)

(if true
  "yes"
  "no")

(if false
  "yes"
  "no")

(if nil
  "yes"
  "no")

2.2 省略else #

clojure
(if true
  "yes")

(if false
  "yes")

省略else时,条件为假返回nil。

2.3 多表达式 #

使用 do 包装多个表达式:

clojure
(if true
  (do
    (println "True!")
    "result")
  "false result")

2.4 嵌套if #

clojure
(defn classify [n]
  (if (< n 0)
    "negative"
    (if (= n 0)
      "zero"
      "positive")))

(classify -5)

(classify 0)

(classify 5)

三、when表达式 #

3.1 基本语法 #

clojure
(when condition
  expr1
  expr2
  ...)

(when true
  (println "Processing...")
  "done")

(when false
  (println "This won't print")
  "done")

3.2 when-not #

clojure
(when-not false
  "not false")

(when-not true
  "won't execute")

3.3 when vs if #

特性 if when
else分支 支持 不支持
多表达式 需要do 自动支持
返回值 条件相关 条件为假返回nil

建议:当不需要else分支时,优先使用 when

四、cond表达式 #

4.1 基本语法 #

clojure
(cond
  condition1 expr1
  condition2 expr2
  :else default-expr)

(defn grade [score]
  (cond
    (>= score 90) "A"
    (>= score 80) "B"
    (>= score 70) "C"
    (>= score 60) "D"
    :else "F"))

(grade 95)

(grade 75)

(grade 50)

4.2 :else关键字 #

clojure
(cond
  false "never"
  false "also never"
  :else "default")

:else 不是特殊语法,只是惯用的默认分支写法。

4.3 无默认分支 #

clojure
(cond
  false "a"
  false "b")

(cond
  false "a"
  false "b"
  :else nil)

五、case表达式 #

5.1 基本语法 #

clojure
(case expr
  value1 result1
  value2 result2
  default-result)

(defn direction [d]
  (case d
    :north "Up"
    :south "Down"
    :east "Right"
    :west "Left"
    "Unknown"))

(direction :north)

(direction :up)

5.2 多值匹配 #

clojure
(defn classify [x]
  (case x
    (1 2 3) "small"
    (4 5 6) "medium"
    (7 8 9) "large"
    "other"))

(classify 2)

(classify 5)

(classify 10)

5.3 case vs cond #

特性 case cond
匹配方式 精确相等 任意条件
性能 O(1) O(n)
编译期 常量 运行时
灵活性

六、if-let和when-let #

6.1 if-let #

clojure
(if-let [binding test]
  then-expr
  else-expr)

(defn process [x]
  (if-let [value (get x :key)]
    (str "Found: " value)
    "Not found"))

(process {:key "hello"})

(process {:other "value"})

6.2 when-let #

clojure
(when-let [binding test]
  expr1
  expr2)

(defn process [x]
  (when-let [value (get x :key)]
    (println "Processing:" value)
    (* value 2)))

(process {:key 5})

(process {:other 1})

6.3 多绑定 #

clojure
(if-let [a 1
         b 2]
  (+ a b)
  0)

(if-let [a 1
         b nil]
  (+ a b)
  0)

所有绑定都必须为真。

七、condp表达式 #

7.1 基本语法 #

clojure
(condp pred expr
  value1 result1
  value2 result2
  default-result)

(defn classify [n]
  (condp = n
    1 "one"
    2 "two"
    3 "three"
    "other"))

(classify 2)

(classify 5)

7.2 自定义谓词 #

clojure
(defn check [n]
  (condp < n
    0 "negative"
    10 "small"
    100 "medium"
    "large"))

(check -5)

(check 5)

(check 50)

(check 500)

7.3 使用函数结果 #

clojure
(condp some [1 2 3 4 5]
  #{0 6 7} :>> inc
  #{4 5 9} :>> dec
  #{1 2 3} :>> #(* % 10))

八、逻辑运算 #

8.1 and #

clojure
(and true true)

(and true false)

(and 1 2 3)

(and 1 nil 3)

(and)

and 返回第一个假值或最后一个值。

8.2 or #

clojure
(or false true)

(or false false)

(or nil 1 2)

(or)

or 返回第一个真值或最后一个值。

8.3 not #

clojure
(not true)

(not false)

(not nil)

(not "hello")

8.4 实用模式 #

clojure
(defn default-name [name]
  (or name "Anonymous"))

(default-name "Alice")

(default-name nil)

(defn all-positive? [a b c]
  (and (pos? a) (pos? b) (pos? c)))

(all-positive? 1 2 3)

(all-positive? 1 -2 3)

九、实践示例 #

9.1 输入验证 #

clojure
(defn validate-user [{:keys [name age email]}]
  (cond
    (empty? name)
    {:error "Name is required"}

    (or (nil? age) (neg? age))
    {:error "Age must be a positive number"}

    (and email (not (re-matches #".+@.+" email)))
    {:error "Invalid email format"}

    :else
    {:valid true}))

(validate-user {:name "" :age 25})

(validate-user {:name "Alice" :age -1})

(validate-user {:name "Alice" :age 25 :email "invalid"})

(validate-user {:name "Alice" :age 25 :email "alice@example.com"})

9.2 状态机 #

clojure
(defn next-state [current event]
  (case [current event]
    [:idle :start] :running
    [:running :pause] :paused
    [:running :stop] :idle
    [:paused :resume] :running
    [:paused :stop] :idle
    current))

(next-state :idle :start)

(next-state :running :pause)

(next-state :paused :resume)

9.3 配置处理 #

clojure
(defn get-config [config key]
  (if-let [value (get config key)]
    value
    (if-let [default (get config :default)]
      default
      nil)))

(get-config {:a 1 :default "N/A"} :a)

(get-config {:a 1 :default "N/A"} :b)

(get-config {:a 1} :b)

9.4 权限检查 #

clojure
(defn check-access [user resource action]
  (cond
    (= (:role user) :admin)
    true

    (and (= (:role user) :user)
         (contains? #{:read :list} action))
    true

    (and (= (:role user) :guest)
         (= action :read)
         (:public resource))
    true

    :else false))

(check-access {:role :admin} {} :delete)

(check-access {:role :user} {} :read)

(check-access {:role :guest} {:public true} :read)

(check-access {:role :guest} {:public false} :read)

十、总结 #

条件表达式速查:

表达式 用途
if 二选一
when 条件执行,无else
cond 多条件分支
case 精确匹配
if-let 绑定+判断
when-let 绑定+条件执行
condp 谓词匹配

关键点:

  1. 条件表达式都有返回值
  2. 只有 falsenil 是逻辑假
  3. whenif 更简洁(无else时)
  4. case 性能最好(编译期常量)
  5. if-let/when-let 简化绑定判断

下一步,让我们学习循环与递归!

最后更新:2026-03-27