关键字与符号 #
一、关键字(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键 | 推荐 | 较少 |
关键点:
- 关键字自身求值,适合作为常量和Map键
- 符号求值为绑定的值,用于变量引用
- 命名空间限定避免冲突
::创建当前命名空间关键字
下一步,让我们学习正则表达式!
最后更新:2026-03-27