为什么您更喜欢:require:refere:all-over:use in clojure

为什么您更喜欢:require:refere:all-over:use in clojure,clojure,coding-style,Clojure,Coding Style,作者在他的著作中写道: Prefer using :require :refer :all over :use in ns macro 他没有解释为什么这是个好主意。有 避免在ns宏中使用的一个很好的理由是?,因为使用:require可以清楚地指示哪个命名空间拥有函数 (:require [clojure.json :as json]) (:require [clojure.xml :as xml]) (json/read "file") (xml/read "file") 如果出现:

作者在他的著作中写道:

Prefer using :require :refer :all over :use in ns macro
他没有解释为什么这是个好主意。有
避免在ns宏中使用的一个很好的理由是?

,因为使用
:require
可以清楚地指示哪个命名空间拥有函数

(:require [clojure.json :as json])
(:require [clojure.xml  :as xml])

(json/read "file")
(xml/read  "file")
如果出现
:使用

(read "file")

如何知道哪些命名空间拥有
read
函数?如果我在维护你的代码,我必须检查
ns
宏并开始搜索每个
use
限定名称空间中的
read
函数。

使用
:require
您只有一个地方定义名称空间导入,您可以轻松地从引用所有函数切换到引用几个函数或只需要名称空间(或随意混合匹配)


我的印象是有两个原因。1) 这样做,您更有可能避免任何名称冲突和/或意外的阴影。2) 这些实践使代码中使用的函数和变量的最终来源更加透明。第一个是非常实际的,凯龙的回答提供了一个很好的例子

第二个更微妙,但如果您使用了大量库,它可能非常重要。假设你是这样做的:

(ns your-namespace
  (:use [library-one]
        [library-two]
        [library-three]
        [library-four]
        [library-five]))
然后在代码后面的某个地方调用:

(important-function some-arg some-other-arg)
例如,如果
库三中定义了
重要函数
,那么您(或试图理解您的代码的人)必须深入挖掘每个库的代码,以了解它的功能,因为没有任何东西可以指明哪个库是它的源代码!实际上,如果您有可用的REPL,您应该能够通过执行以下操作来解决它:

your-namespace> `important-function
> library-three/important-function
但是,这种隐藏的信息可能不是最好的事情,对其他人(包括你未来的自己)谁可能希望了解你的代码。另一方面,
:require
d库总是带有前缀。因此,您的代码应该如下所示:

(ns your-namespace
  (:require [library-one]
            [library-two]
            [library-three]
            [library-four]
            [library-five]))

...

(library-three/important-function some arg some-other-arg)
这使得
重要功能的定义非常明确。请注意,这相当于指定
:请参阅:all
。尽管
:reference:all
可以向其他人表明您特别考虑了要引用的变量,并有意识地决定将该库中的所有变量都包含在内

如果你不担心名字冲突…那么你可能应该担心。但是,如果您仍然不知道,并且您想清楚vars的来源,那么您可以始终将
:与
:仅
一起使用
。例如:

(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)
显然,如果您是
:使用带有空
:仅
向量的库,那么您最好不要
:首先使用
它们,我只想与前面的示例相结合。执行
:require
可能看起来很冗长,但您可以通过使用
:as
别名来缩短它。片段示例:

(ns your-namespace
  (:require [library-three :as L3]))

(L3/important-function some-arg some-other-arg)

另请参见Clojure中的关于库和名称空间的问题和。

我建议您查看导致此规则的。我们可以找到核心理由。我将在这里包括讨论的开始:

之前已经讨论过ns的复杂性 宏。特别是:use导致引用所有变量 违约被普遍认为是不幸的,而 对新手来说,使用和需求是概念开销的来源 语言。我们无法改变这样一个事实:使用指的是一切 默认设置,而不破坏大量现有代码。但那是真的 可能增强:需要支持引用指定变量, 让我们可以自由地反对或不鼓励使用:use

而不是这种形式:

(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))
我们可以这样做:

(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作为 不同于:需求是可取的,我同意我们 不应该将Clojure变量和Java类混为一谈

很少有引用命名空间中的所有变量的情况 可接受(尤其是在编写测试名称空间时 将所有clojure.test和命名空间都引入 测试)所以我们可能应该支持:refere:all用于这种情况,如 只要不是默认值


关注点分离
require
允许您加载名称空间,
reference
允许您定义如何引用这些名称空间中的变量<代码>使用
完成了这两个问题。

问题不是关于:as,而是关于:refere:all。当使用:refere时,根本不指定名称空间。编辑建议:
:json
:xml
应该是符号,而不是关键字。另外,
:require
关键字在
(ns…
之外无效,这可能会产生误导。@OmriBernstein谢谢,我更正了符号部分。但另一方面,我的意图是说明限定名称。这应该是公认的答案。其他答案集中于解释为什么引用所有变量通常是个坏主意,但不要以任何方式讨论
:refere:all
,那么,引用所有变量!理由是:社区已经决定
:use
是一个不好的默认值,并鼓励使用不好的代码,因此它的存在太糟糕了,因此让我们假装它不存在,通过始终使用
:require:refere:all
,即使它做的事情完全相同。
(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))