Clojure 块封装与局部封装-let
当我有一个独立于参数的函数的相关数据时,我什么时候应该支持块封装而不是局部封装 我应该在什么时候使用:Clojure 块封装与局部封装-let,clojure,let,Clojure,Let,当我有一个独立于参数的函数的相关数据时,我什么时候应该支持块封装而不是局部封装 我应该在什么时候使用: (let [hello "Hello "] (defn do-greet "Print a greeting." [name] (println (str hello name)))) 与: (defn do-greet "Print a greeting." [name] (let [hello "Hello "] (println (str
(let [hello "Hello "]
(defn do-greet
"Print a greeting."
[name]
(println (str hello name))))
与:
(defn do-greet
"Print a greeting."
[name]
(let [hello "Hello "]
(println (str hello name))))
肯定是这样的:
(defn do-greet
"Print a greeting."
[name]
(let [hello "Hello "]
(println (str hello name))))
如果
hello
仅在该单个函数中使用,则将let
放在函数本身中更有意义。如果您打算在多个函数中使用hello
,那么将let
放在这些函数之外并围绕这些函数进行包装是很有意义的。这是一种风格选择,可能至少要取决于计算值的成本。考虑一下:
(defn nth-prime [n] ...)
(defn f [x]
(let [factor (nth-prime 10000)]
(* x factor)))
(let [factor (nth-prime 10000)]
(defn g [x]
(* x factor)))
每次调用
f
时重新计算一个昂贵的常量是浪费的,而g
使用了一种简单的技术来避免这样做。如果您想像在词汇范围的代码块中使用静态常量一样使用值,前者是一个合理的选择。通常,您会在以下情况下执行此操作:
- 该值的计算代价很高,并且在加载命名空间时只需执行一次
- 该值是真正的常量,即不会在函数调用期间更改
- 该值将在多个函数定义中使用(即,在let块中放置多个defn)
- (可能?)因为您希望在宏扩展中使用该值,而将let嵌入宏扩展本身将增加不必要的复杂性
- 它更地道
- 它允许函数定义处于顶层,这有利于代码的可读性/理解性
- 它允许值根据不同的函数调用而变化
- 它更好地反映了在本地上下文中使用该值的意图
(让[hello(slurp(clojure.java.io/resource“hello”)])…
。我把我的问题留得更笼统一些,因为我不知道这些形式实际上是如何评估的,以及相应的权衡是什么。在某些情况下,它与风格没有任何关系。如果需要该值在两个不同的函数中可用,则必须使该值在这些函数的作用域之上可用。另外,请看@amalloy的回答。如果说运行时行为(性能)有所不同,我认为这不是一种风格选择。只是因为在提问者的例子中,实际上没有什么不同,这是风格上的。我喜欢这样,你涵盖了更多的要点。我不确定您的宏扩展点是否有效,因为您可以将let环绕扩展,但仍在函数内部。为了便于阅读,我建议将文体选择与语义差异分开。(值可以根据不同的函数调用而变化)。