我理解在Clojure中关键字是使用:keyword
,但是::
是用来做什么的?为什么它看起来像有一个绑定?
user=> :foo
:foo
user=> ::foo
:user/foo
我理解在Clojure中关键字是使用:keyword
,但是::
是用来做什么的?为什么它看起来像有一个绑定?
user=> :foo
:foo
user=> ::foo
:user/foo
::
关键字也可以用于解决命名空间别名。例如,如果 foo
是 clojure.core
的别名,则 ::foo/bar
将计算为:clojure.core/bar
。如果 foo
不能解析为命名空间,则会引发读取器异常。::
是一个“完全限定命名空间”(Fully-Qualified NameSpace)的表示,或者我喜欢称之为FQNS。它与FQDN的概念类似。它(::
)可以“扩展”为一个“必需别名”(例如,::str
是指向(:require [clojure.string :as str])
中点部分的别名),或者当前命名空间(例如,::
是指向当前文件顶部的(ns myproj.myns ...)
的别名)。与不带/
的裸键相比,它解析后会有一个/
。
/
的形式)可以有几种形式,并且应该与基本的“非限定”关键字语法进行比较,该语法使用单个:
而没有/
。FQNS的“快捷”关键字语法使用前导冒号(::
)。::k
是 "local",::aa/k
是 "aliased")::
视为代表被压缩的完整长名称。它们可以包含点,但我认为破折号更清晰。注意后者包含一个/
。:bb.cc.dd/k
)aa.bb.cc
是祖父,bb
是父亲,cc
是孩子。显式的完全限定命名空间只有一个:
,但包含一个/
(例如::aa/bb
,:cc.dd/ee
)。:k
)
这是你从第一天就知道的基本不合格的关键。
我发现让编辑器明显地显示出你正在观察的形状是很有帮助的。在屏幕截图中,你可以看到::
是红色表示当前的NS,显式完整的NS是蓝色,"别名"NS是绿色,最后的"key"是紫色。
在这个示例中(您可以在REPL中尝试),请注意这些“解析”(请参见尾部注释)。这里有超过十几种情况,每一种都有所不同。
(ns proj.ns1)
(ns proj.area.ns2)
(ns proj.ns3
(:require
[clojure.string :as str]
[clojure.data.avl :as d-a] ; or da or avl or just a; be consistent across code base
[clojure.data.zip :as d.z] ; using dots in alias is confusing IMO
[proj.area.ns2 :as ns2] ; some fns being used
[proj.ns1 :as-alias ns3])) ; keying convenience, new in v1.11, avoids circular deps
(def m "A contrived map demonstrating various key shapes"
{:aa "good" ;=> :aa ; typical: basic unqualified key
::bb "good" ;=> :proj.ns3/bb ; typical: note that / is implicitly added
::str "bad" ;=> :proj.ns3/str ; missing key
:ns3/cc "weird" ;=> :ns3/cc ; missing full ns despite alias
:proj.area.ns4/dd "ok" ;=> :proj.area.ns4.dd ; ns might not exist but ok
::ns2/ff "good" ;=> :proj.area.ns2/ff ; common practice
:proj.area.ns2/gg "ok" ;=> :proj.area.ns2/gg ; but this is why we have `:as-alias`
:proj.ns1/hh "bad" ;=> :proj.ns1/hh ; clearer to just use `::` for cur ns
:str/ii "bad" ;=> :str/ii ; an accident: str not expanded
::str/jj "good" ;=> :clojure.string/jj ; and typical
::kk.ll "so-so" ;=> :proj.ns3/kk.ll ; confusing to have dots in actual key
::d-a/mm.nn "so-so" ;=> :clojure.data.json/mm.nn ; again, dots in key
::d-a/oo "good" ;=> :clojure.data.json/oo ; typical
::d.z/pp "so-so" ;=> :proj.ns3/pp ; dots in qualifier diff from ns structure
:random/qq "good" ;=> :random/qq ; qualified, but not a real ns
:other.random/rr "good" ;=> :other.random/rr ; qualified, but not a real ns
})
:jj
键在clojure.string
命名空间中不存在,但这并不妨碍你使用它。
::
)中扩展时添加了/
。因此,这三个是需要记住的重点内容。WRITTEN RESOLVED
:aa => :aa (bare)
::bb => :proj.ns1/bb (qualified)
::ns3/cc => :proj.ns3/cc (qualified, slash explicit)
(let [{:keys [aa]} m] aa) ; "good" (typical)
(let [{:keys [:aa]} m] aa) ; "good" (also works with :)
(let [{:keys [::aa]} m] aa) ; nil
(let [{:keys [::bb]} m] bb) ; "good"
(let [{:keys [ns2/ff]} m] ff) ; nil
(let [{:keys [:ns2/ff]} m] ff) ; nil
(let [{:keys [::ns2/ff]} m] ff) ; "good"
(let [{:keys [ns3/cc]} m] cc) ; "weird"
(let [{:keys [:ns3/cc]} m] cc) ; "weird"
(let [{:keys [other.random/rr]} m] rr) ; "good"
(let [{:keys [:other.random/rr]} m] rr) ; "good"
这是 Clojure 语法中一个棘手的领域,但它是日常代码的重要组成部分。如果你遵循类似下面这些 NS 风格指南,可以帮助减少混乱:
请注意,关于别名约定(str
vs string
,别名中的点等)可能存在争议,但关键是在你的规则上确立和保持一致。