Kun*_*ngi 5 coding-style clojure
作者在《Clojure风格指南》中写道:
Prefer using :require :refer :all over :use in ns macro
Run Code Online (Sandbox Code Playgroud)
他没有给出任何解释为什么这是一个好主意。是否有充分的理由避免在ns宏中使用:use?
我建议您看一下导致该规则的原始讨论。核心原理可以在这里找到。我将在这里开始讨论:
以前已经讨论过ns宏的复杂性。特别地,:use导致所有var默认被引用的事实被普遍认为是不幸的,而use和require之间的区别是新手对该语言的概念上的负担。我们不能改变这样的事实:默认情况下:use引用所有内容而不会破坏很多现有代码。但是可能可以增强:require以支持引用指定的var,从而使我们可以随意弃用或以其他方式阻止:use的使用。
而不是这种形式:
Run Code Online (Sandbox Code Playgroud)(ns mork.test (:use [mork.stats :only [summarize-group]] [mork.utils :only [strip resolve-fn]] [clojure.test]) (:require [mork.view :as view] [clojure.java.io :as io] [cheshire.core :as json]) (:import (java.io PushbackReader))我们可以这样使用:
Run Code Online (Sandbox Code Playgroud)(ns mork.test (:require [mork.stats :refer [summarize-group]] [mork.utils :refer [strip resolve-fn]] [clojure.test :refer :all] [mork.view :as view] [clojure.java.io :as io] [cheshire.core :as json]) (:import (java.io PushbackReader))在先前的线程中已经达成共识,保持:import作为与:require不同的概念是可取的,而且我同意我们不应该在Clojure vars和Java类之间混用。
在少数情况下,可以接受名称空间中的所有vars是可以接受的(特别是在编写测试名称空间时,引入所有clojure.test和被测试的名称空间似乎是合理的),因此我们应该支持:refer:all一种情况,只要它不是默认值即可。
我的印象是有两个原因。1) 这样做,您更有可能避免任何名称冲突和/或意外的掩盖。2) 这种做法使代码中使用的函数和变量的最终来源更加透明。第一个非常实用,Chiron 的答案提供了很好的演示。
第二个更微妙,但如果您使用很多库,它可能非常重要。假设你这样做:
(ns your-namespace
(:use [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
Run Code Online (Sandbox Code Playgroud)
然后在代码中的某个地方,您调用:
(important-function some-arg some-other-arg)
Run Code Online (Sandbox Code Playgroud)
important-function例如,如果在 中定义library-three,那么您(或任何试图理解您的代码的人)必须深入研究每个库的代码以找出它的作用——因为没有任何东西可以表明哪个库是它的来源!好吧,实际上,如果您有可用的 REPL,您应该能够通过执行以下操作来弄清楚:
your-namespace> `important-function
> library-three/important-function
Run Code Online (Sandbox Code Playgroud)
但这种隐藏信息对于其他可能希望了解您的代码的人(包括未来的您)来说可能不是最好的选择。另一方面,:required 库总是带有前缀。因此,您的代码将如下所示:
(ns your-namespace
(:require [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
...
(library-three/important-function some arg some-other-arg)
Run Code Online (Sandbox Code Playgroud)
这使得important-function定义在哪里非常清楚。请注意,这应该等同于指定:refer :all. 虽然:refer :all可以向其他人表明您特别考虑了要引用哪些变量,并有意识地决定包含该库中的所有变量。
如果您不担心名称冲突……那么您可能应该担心。但如果你仍然不知道,并且你想清楚 vars 的来源,那么你总是可以:use使用:only. 例如:
(ns your-namespace
(:use [library-one :only []]
[library-two :only []]
[library-three :only [important-function]]
[library-four :only []]
[library-five :only []]))
...
(important-function some arg some-other-arg)
Run Code Online (Sandbox Code Playgroud)
显然,如果您正在:use使用空白:only向量的库,那么您最好一:use开始就不要使用它们,我只是想与前面的示例统一。这样做:require可能看起来很冗长,但您始终可以通过使用别名来缩短它:as。片段示例:
(ns your-namespace
(:require [library-three :as L3]))
(L3/important-function some-arg some-other-arg)
Run Code Online (Sandbox Code Playgroud)
另请参阅这个 SO问题,以及有关 Clojure 中的库和命名空间的指南。