Clojure - 1 个函数的 2 个版本。哪个更惯用?
Posted
技术标签:
【中文标题】Clojure - 1 个函数的 2 个版本。哪个更惯用?【英文标题】:Clojure - 2 versions of 1 function. Which is more idiomatic? 【发布时间】:2012-02-24 19:07:24 【问题描述】:在此处包含的两个函数中,哪一个更惯用?两者都不代表可以被认为是好的 Clojure 的东西吗?有没有更优雅的方式来实现这一点?寻找一些关于风格/方向的建设性批评。
(在github上:https://github.com/jtrim/clojure-sandbox/blob/master/bit-sandbox/src/bit_sandbox/core.clj#L25)
这个函数的两个版本都采用数字表示的字节向量,并且 将字节转换为数字。例如
(bytes-to-num [0 0 0 0]) ;=> number `0`
(bytes-to-num [0 0 0 255]) ;=> number `255`
(bytes-to-num [0 0 1 0]) ;=> number `256`
; etc...
v1:循环/重复
在每个递归级别,有问题的字节 左移一个对应于字节数的数字 给定的递归级别,然后添加到运行总和中 返回或传递到另一个级别。
(defn bytes-to-num-v1 [vec-bytes]
(loop [sum 0, the-bytes vec-bytes]
(if (empty? the-bytes)
sum
(recur
(+ sum (shifted-byte (first the-bytes) (count (rest the-bytes))))
(rest the-bytes)))))
v2:减少
v2 使用 [sum position] 的累加器减少字节向量,其中:
sum:移位字节的运行总和 位置:从零开始的索引(注意:从右侧开始,而不是从左侧开始) 向量中的当前字节。用于确定要左移多少位 有问题的字节。:
(defn bytes-to-num-v2 [vec-bytes]
(first (reduce
(fn [acc, the-byte]
[(+ (first acc) (shifted-byte the-byte (last acc))) (dec (last acc))])
[0 (dec (count vec-bytes))]
vec-bytes)))
为了完整性,shifted-byte
函数的来源:
(defn shifted-byte [num-byte-value, shift-by]
(bit-shift-left
(bit-and num-byte-value 0xFF)
(* shift-by 8)))
【问题讨论】:
【参考方案1】:您正在尝试将字节转换为无符号大整数,对吗?
在这种情况下,您可能想要这样的东西:
(defn bytes-to-num [bytes]
(reduce (fn [acc x] (+ x (* 256 acc))) bytes))
一般cmets:
Reduce通常是比循环/递归更好、更惯用的选项 如果你能提供帮助,你真的不想拉一个位置索引或者,您可以使用 Java 互操作直接使用接受字节数组的 BigInteger 构造函数。这里唯一的技巧是 Java 需要有符号字节,所以你需要先做一点转换:
(defn to-signed-byte [x] (.byteValue x))
(BigInteger. (byte-array (map to-signed-byte [ 0 0 0 255])))
=> 255
【讨论】:
非常好。加载更简单,更容易阅读。感谢您的反馈!to-signed-byte
也可以使用Byte/valueOf
。 (defn t-s-b [x] (Byte/valueOf (byte x)))
。它会为您完成转换。
@kotarak - 不确定是否有效,因为 (byte x) 失败,任何高于 127 的值......据我所知,对于未经检查的强制整数类型。
实际上从头开始。 (.byteValue x) 似乎确实有效......使用此编辑的答案
啊。哎呀。对不起。我的意思是.byteValue
。以上是关于Clojure - 1 个函数的 2 个版本。哪个更惯用?的主要内容,如果未能解决你的问题,请参考以下文章