在Clojure中返回表达式序列中非最后一个表达式的值的惯用方法

在Clojure中返回表达式序列中非最后一个表达式的值的惯用方法,clojure,let,Clojure,Let,假设我有以下函数从字节缓冲区获取数值: (defn get-from-bytebuffer ([^ByteBuffer buffer width endianness] (let [buffer-endianness (.order buffer)] (.order buffer endianness) (cond (= width 1) (.get buffer) (= width 2) (.getShort buffer)

假设我有以下函数从字节缓冲区获取数值:

(defn get-from-bytebuffer
  ([^ByteBuffer buffer width endianness]
    (let [buffer-endianness (.order buffer)]
      (.order buffer endianness)
      (cond
        (= width 1) (.get buffer)
        (= width 2) (.getShort buffer)
        (= width 4) (.getInt buffer)
        (= width 8) (.getLong buffer))
      (.order buffer buffer-endianness))))
用户可以指定正在读取的数字的尾数。为了将副作用降至最低,函数首先获取缓冲区的当前字节顺序,将其设置为用户指示的顺序,然后恢复旧的endianness。问题是
let
主体中最后一个表达式的值是
let
表达式的值,但我需要
cond
的值。更一般地说,我有一些关于表达式的序言/尾声代码,但我希望返回表达式的结果(即封闭表达式的值)

我提出的简单解决方法只是将
cond
的值绑定到另一个let表达式中,然后将其作为最后一个表达式,如下所示:

(defn get-from-bytebuffer-fix
  ([^ByteBuffer buffer width endianness]
    (let [buffer-endianness (.order buffer)]
      (.order buffer endianness)
      (let [result (cond
                     (= width 1) (.get buffer)
                     (= width 2) (.getShort buffer)
                     (= width 4) (.getInt buffer)
                     (= width 8) (.getLong buffer))]
      (.order buffer buffer-endianness)
      result))))
但这让人觉得很尴尬。Clojure是否有一种惯用的/恰当的方式,用一些开场白/尾声代码围绕一个表达式,然后返回该表达式的值?

您可以这样写:

(defn get-from-bytebuffer
  ([^ByteBuffer buffer width endianness]
    (let [buffer-endianness (.order buffer)
          _ (.order buffer endianness)
          result (cond
                   (= width 1) (.get buffer)
                   (= width 2) (.getShort buffer)
                   (= width 4) (.getInt buffer)
                   (= width 8) (.getLong buffer))]
      (.order buffer buffer-endianness)
      result)))
请注意let表单中的
\
。它只是忽略返回值,允许您在该位置执行几乎任何操作

我不会说它是惯用的,在某种程度上说它“奇怪”,因为它在let绑定中有副作用,但我以前在类似的场景中使用过这种风格,到目前为止,我对它很满意

否则,我会采取你所展示的双让方法


希望这有帮助。

也许下面的备选方案之一是可以接受的

(let [buffer-endianness (.order buffer)
      _ (.order buffer endianness)
      result (cond
               (= width 1) (.get buffer)
               (= width 2) (.getShort buffer)
               (= width 4) (.getInt buffer)
               (= width 8) (.getLong buffer))
      _ (.order buffer buffer-endianness)]
  result)

(let [buffer-endianness (.order buffer)]
  (try 
    (.order buffer endianness)
    (cond
      (= width 1) (.get buffer)
      (= width 2) (.getShort buffer)
      (= width 4) (.getInt buffer)
      (= width 8) (.getLong buffer))
    (finally (.order buffer buffer-endianness))))

(defn return-nth [n & exprs]
  (nth exprs n))

(return-nth 1
  'exp-0
  'exp-1
  'exp-2)

(nth ['exp-0 'exp-1 'exp-2] 1)
还要注意

(cond
  (= width 1) (.get buffer)
  (= width 2) (.getShort buffer)
  (= width 4) (.getInt buffer)
  (= width 8) (.getLong buffer))
可以写

(case width
  1 (.get buffer)
  2 (.getShort buffer)
  4 (.getInt buffer)
  8 (.getLong buffer))

这不仅是惯用用法,也是我所看到的唯一一种使用方式——作为将被忽略的值的绑定。不过,要明确的是,u是一个有效的符号-
(让[1](inc))
->2。另请参见和前面的问题。