关键字与符号 #

一、关键字(Keyword) #

1.1 什么是关键字 #

关键字是Clojure中一种特殊的标识符,以冒号开头:

clojure
:name

:user/id

:ns/example

:foo/bar/baz

关键字的特点:

  • : 开头
  • 自身求值为自身
  • 常用作Map的键
  • 可带命名空间限定

1.2 关键字创建 #

clojure
:name

(keyword "name")

(keyword "user" "id")

(keyword "user/id")

1.3 命名空间关键字 #

clojure
:user/name

:my.app.config/database-url

::name

*ns*

:: 创建当前命名空间限定的关键字:

clojure
(ns my-app.core)

::name

1.4 关键字作为函数 #

关键字可以作为函数使用,从Map中取值:

clojure
(def person {:name "Alice" :age 30})

(:name person)

(:age person)

(:email person)

(:email person "N/A")

1.5 关键字操作 #

clojure
(name :user/name)

(namespace :user/name)

(keyword "name")

(keyword "user" "name")

(qualified-keyword? :user/name)

(simple-keyword? :name)

1.6 关键字判断 #

clojure
(keyword? :name)

(keyword? "name")

(keyword? 'name)

二、符号(Symbol) #

2.1 什么是符号 #

符号是Clojure中的标识符,用于命名变量、函数等:

clojure
x

my-variable

my-function

+

map

user/name

符号的特点:

  • 用于引用值
  • 求值时返回绑定的值
  • 可带命名空间限定
  • 是代码的基本组成单元

2.2 符号创建 #

clojure
'name

(symbol "x")

(symbol "user" "name")

(symbol "user/name")

2.3 符号求值 #

clojure
(def x 42)

x

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

greet

(greet "World")

2.4 符号操作 #

clojure
(name 'user/name)

(namespace 'user/name)

(symbol "name")

(symbol "user" "name")

(qualified-symbol? 'user/name)

(simple-symbol? 'name)

2.5 符号判断 #

clojure
(symbol? 'x)

(symbol? :x)

(symbol? "x")

三、关键字 vs 符号 #

3.1 核心区别 #

特性 关键字 符号
语法 :name name'name
求值 自身 查找绑定值
用途 常量标识符 变量名
作为键 常用 较少

3.2 求值行为 #

clojure
(def x 42)

x

:x

(eval 'x)

(eval :x)

3.3 使用场景 #

关键字:用于Map键、枚举值、选项

clojure
{:name "Alice" :age 30}

(def status :running)

(case status
  :running "Processing..."
  :stopped "Idle"
  :error "Failed!")

符号:用于变量名、函数名

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

(let [x 10
      y 20]
  (+ x y))

四、命名空间限定 #

4.1 完全限定名 #

clojure
:user/name

:clojure.core/map

'clojure.core/map

4.2 自动解析关键字 #

:: 创建当前命名空间限定的关键字:

clojure
(ns my-app.core)

::name

::my-app.core/name

4.3 别名关键字 #

clojure
(ns my-app.core
  (:require [my-app.utils :as utils]))

::utils/helper

4.4 命名空间操作 #

clojure
(name :user/name)

(namespace :user/name)

(name 'user/name)

(namespace 'user/name)

(qualified-keyword? :user/name)

(qualified-symbol? 'user/name)

五、自动解析关键字 #

5.1 在Map中使用 #

clojure
(ns my-app.core)

{::name "Alice" ::age 30}

5.2 在spec中使用 #

clojure
(require '[clojure.spec.alpha :as s])

(s/def ::name string?)

(s/def ::age pos-int?)

(s/def ::person (s/keys :req [::name ::age]))

5.3 在Datomic中使用 #

clojure
{:db/ident :user/name
 :db/valueType :db.type/string
 :db/cardinality :db.cardinality/one}

六、实践应用 #

6.1 配置Map #

clojure
(def config
  {:database/host "localhost"
   :database/port 5432
   :database/name "myapp"
   :app/environment :production})

(:database/host config)

(get-in config [:database/host])

6.2 枚举值 #

clojure
(defn process-status [status]
  (case status
    :pending "Waiting..."
    :running "Processing..."
    :completed "Done!"
    :failed "Error!"
    "Unknown status"))

6.3 多态派发 #

clojure
(defmulti draw :shape)

(defmethod draw :circle [shape]
  (str "Drawing circle with radius " (:radius shape)))

(defmethod draw :rectangle [shape]
  (str "Drawing rectangle " (:width shape) "x" (:height shape)))

(draw {:shape :circle :radius 5})

(draw {:shape :rectangle :width 10 :height 20})

6.4 元数据 #

clojure
(def ^:private secret-value 42)

(def ^:dynamic *config* {:debug true})

(meta #'secret-value)

七、命名约定 #

7.1 关键字命名 #

clojure
:user-name

:user/name

:db.type/string

:http.status/ok

约定

  • 使用kebab-case
  • 命名空间限定用于区分领域
  • 点号用于层次结构

7.2 符号命名 #

clojure
(def my-variable 10)

(defn my-function [x] x)

(defn valid? [x] true)

(defn process! [data] (swap! data inc))

(def *config* {:debug true})

约定

  • 变量/函数:kebab-case
  • 谓词函数:以 ? 结尾
  • 副作用函数:以 ! 结尾
  • 动态变量:用 *星号* 包围

八、高级技巧 #

8.1 关键字与字符串转换 #

clojure
(name :user/name)

(str :name)

(keyword "name")

(keyword "user" "name")

8.2 符号与关键字转换 #

clojure
(keyword 'name)

(keyword 'user/name)

(symbol (name :name))

(symbol (namespace :user/name) (name :user/name))

8.3 动态创建 #

clojure
(defn make-keyword [ns name]
  (keyword ns name))

(make-keyword "user" "id")

(defn make-symbol [ns name]
  (symbol ns name))

(make-symbol "user" "id")

8.4 解析限定名 #

clojure
(defn parse-qualified [kw]
  {:namespace (namespace kw)
   :name (name kw)})

(parse-qualified :user/name)

九、常见问题 #

9.1 关键字 vs 字符串作为Map键 #

clojure
(def m1 {:name "Alice"})
(def m2 {"name" "Alice"})

(:name m1)

(:name m2)

(get m2 "name")

(get m2 :name)

建议:优先使用关键字作为Map键。

9.2 符号未定义错误 #

clojure
undefined-symbol

解决:确保符号已定义或使用引号:

clojure
'undefined-symbol

9.3 命名空间问题 #

clojure
(ns my-app.core)

::name

(ns my-app.utils)

::name

不同命名空间的同名关键字是不同的。

十、总结 #

关键字与符号对比:

特性 关键字 符号
语法 :name name
求值 自身 绑定值
用途 常量标识 变量名
Map键 推荐 较少

关键点:

  1. 关键字自身求值,适合作为常量和Map键
  2. 符号求值为绑定的值,用于变量引用
  3. 命名空间限定避免冲突
  4. :: 创建当前命名空间关键字

下一步,让我们学习正则表达式!

最后更新:2026-03-27