阻塞封装与本地封装 - 让

时间:2012-11-02 19:11:21

标签: 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 hello name))))

4 个答案:

答案 0 :(得分:6)

如果要在词法范围的代码块中使用类似静态常量的值,前者是一个合理的选项。通常情况下,如果符合以下条件,您将执

  • 计算价值昂贵,而且只想在加载命名空间时执行一次
  • 该值是真正恒定的,即不会在函数调用中发生变化
  • 该值将用于多个函数定义(即您在let块中放置多个defns)
  • (可能?)因为你想在宏扩展中使用这个值,并且在宏扩展中嵌入let会增加不必要的复杂性。

在大多数其他情况下,后一版本可能更受欢迎,这有几个原因:

  • 这是更惯用的
  • 它允许函数定义位于顶层,这对于代码可读性/理解力更好
  • 它允许值在不同的函数调用中变化
  • 它更好地反映了在本地环境中使用该值的意图

答案 1 :(得分:5)

这是一种风格选择,应该至少可以依赖于计算价值的成本。请考虑一下:

(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使用一种简单的技术来避免这样做。

答案 2 :(得分:2)

如果hello仅用于该单个函数,则将let放在函数本身中会更有意义。如果您要在多个函数中使用hello,那么将let放在那些函数外面是有意义的。

答案 3 :(得分:1)

绝对是这样的:

(defn do-greet
  "Print a greeting."
  [name]
  (let [hello "Hello "]
    (println (str hello name))))