函数定义 #

一、函数基础 #

函数是Clojure的核心。作为函数式编程语言,Clojure中的函数是一等公民,可以像数据一样传递和操作。

1.1 使用defn定义函数 #

clojure
(defn greet [name]
  (str "Hello, " name "!"))

(greet "World")

1.2 函数组成部分 #

clojure
(defn function-name
  "Documentation string"
  [parameters]
  (body))
部分 说明
defn 定义函数的宏
function-name 函数名(符号)
"doc-string" 文档字符串(可选)
[parameters] 参数向量
(body) 函数体表达式

1.3 查看文档 #

clojure
(defn square
  "Returns the square of a number.
   Example: (square 5) => 25"
  [x]
  (* x x))

(doc square)

二、参数 #

2.1 无参数函数 #

clojure
(defn pi []
  3.14159)

(pi)

2.2 单参数函数 #

clojure
(defn double-it [x]
  (* x 2))

(double-it 5)

2.3 多参数函数 #

clojure
(defn add [a b]
  (+ a b))

(defn greet [first-name last-name]
  (str "Hello, " first-name " " last-name))

(greet "John" "Doe")

2.4 可变参数 #

使用 & 收集剩余参数:

clojure
(defn sum-all [& numbers]
  (apply + numbers))

(sum-all 1 2 3 4 5)

(defn greet-all [greeting & names]
  (str greeting ", " (clojure.string/join ", " names)))

(greet-all "Hello" "Alice" "Bob" "Carol")

2.5 混合参数 #

clojure
(defn format-message [prefix & parts]
  (str prefix ": " (clojure.string/join " " parts)))

(format-message "ERROR" "File" "not" "found")

三、多参数列表 #

Clojure支持函数重载,根据参数数量执行不同逻辑:

3.1 基本多参数列表 #

clojure
(defn greet
  ([name]
   (greet "Hello" name))
  ([greeting name]
   (str greeting ", " name "!")))

(greet "Alice")

(greet "Hi" "Bob")

3.2 默认参数 #

clojure
(defn make-point
  ([x y] (make-point x y 0))
  ([x y z]
   {:x x :y y :z z}))

(make-point 1 2)

(make-point 1 2 3)

3.3 完整示例 #

clojure
(defn calculate
  ([x] (* x x))
  ([x y] (+ x y))
  ([x y z] (+ x y z)))

(calculate 5)

(calculate 3 4)

(calculate 1 2 3)

四、函数体 #

4.1 隐式do #

函数体可以包含多个表达式,返回最后一个:

clojure
(defn process [x]
  (println "Processing:" x)
  (let [result (* x 2)]
    (println "Result:" result)
    result))

(process 5)

4.2 使用let #

clojure
(defn calculate-area [width height]
  (let [area (* width height)]
    (str "Area: " area " square units")))

(calculate-area 5 3)

4.3 条件表达式 #

clojure
(defn absolute [x]
  (if (neg? x)
    (- x)
    x))

(absolute -5)

(absolute 5)

五、函数元数据 #

5.1 添加元数据 #

clojure
(defn ^:private helper []
  "internal helper")

(defn ^String process [s]
  (str "Processed: " s))

(meta #'helper)

5.2 常用元数据 #

clojure
(defn ^:dynamic config []
  {:debug true})

(defn ^:const max-value []
  100)

(defn ^:deprecated old-function []
  "Use new-function instead")

六、私有函数 #

6.1 defn- #

clojure
(defn- internal-helper []
  "This is private")

(defn public-api []
  (internal-helper))

私有函数只能在定义它的命名空间内使用。

6.2 元数据方式 #

clojure
(defn ^:private another-helper []
  "Also private")

七、前置/后置条件 #

7.1 使用:pre和:post #

clojure
(defn divide [a b]
  {:pre [(not= b 0)]
   :post [(number? %)]}
  (/ a b))

(divide 10 2)

(divide 10 0)

7.2 多个条件 #

clojure
(defn calculate-bmi [weight height]
  {:pre [(pos? weight) (pos? height)]
   :post [(<= 10 % 50)]}
  (/ weight (* height height)))

(calculate-bmi 70 1.75)

八、函数作为值 #

8.1 函数是一等公民 #

clojure
(defn apply-twice [f x]
  (f (f x)))

(apply-twice inc 5)

(apply-twice #(* % 2) 3)

8.2 返回函数 #

clojure
(defn make-adder [n]
  (fn [x] (+ x n)))

(def add5 (make-adder 5))
(def add10 (make-adder 10))

(add5 3)

(add10 3)

8.3 函数组合 #

clojure
(defn compose [f g]
  (fn [x]
    (f (g x))))

(def add1-then-double (compose #(* % 2) inc))

(add1-then-double 4)

(comp inc #(* % 2))

九、常用函数 #

9.1 apply #

clojure
(apply + [1 2 3 4 5])

(apply + 1 2 [3 4 5])

(apply str ["a" "b" "c"])

9.2 partial #

clojure
(def add5 (partial + 5))

(add5 3)

(def greet-hello (partial str "Hello, "))

(greet-hello "World")

9.3 comp #

clojure
(def inc-then-double (comp #(* % 2) inc))

(inc-then-double 4)

(def process (comp str/upper-case str/reverse))

(process "hello")

9.4 complement #

clojure
(def not-empty? (complement empty?))

(not-empty? [])

(not-empty? [1 2 3])

9.5 constantly #

clojure
(def always-5 (constantly 5))

(always-5)

(always-5 1 2 3)

9.6 identity #

clojure
(identity 42)

(filter identity [1 nil 2 nil 3])

十、实践示例 #

10.1 构建器模式 #

clojure
(defn make-person
  ([name] (make-person name nil nil))
  ([name age] (make-person name age nil))
  ([name age email]
   (cond-> {:name name}
     age (assoc :age age)
     email (assoc :email email))))

(make-person "Alice")
(make-person "Bob" 30)
(make-person "Carol" 25 "carol@example.com")

10.2 策略模式 #

clojure
(defn calculate [strategy a b]
  (strategy a b))

(defn add [a b] (+ a b))
(defn multiply [a b] (* a b))
(defn subtract [a b] (- a b))

(calculate add 5 3)
(calculate multiply 5 3)
(calculate subtract 5 3)

10.3 装饰器模式 #

clojure
(defn with-logging [f]
  (fn [& args]
    (println "Calling with args:" args)
    (let [result (apply f args)]
      (println "Result:" result)
      result)))

(defn add [a b]
  (+ a b))

(def logged-add (with-logging add))

(logged-add 3 4)

十一、总结 #

函数定义要点:

特性 语法
基本定义 (defn name [params] body)
文档字符串 (defn name "doc" [params] body)
可变参数 (defn name [x & rest] body)
多参数列表 (defn name ([x] ...) ([x y] ...))
私有函数 (defn- name ...)

关键点:

  1. 函数是一等公民
  2. 支持多参数列表重载
  3. 可变参数使用 &
  4. 元数据控制可见性和行为
  5. 前置/后置条件验证

下一步,让我们学习高阶函数!

最后更新:2026-03-27