Clojure 类型转换不会发生

Clojure type conversion doesn't take place

我有以下函数可以给我一个散列图:

(build-quarter-note-group 60)
;;=> {0.0 "c'", 2.0 "cisis'", -2.0 "ceses'", 0.5 "cih'", -0.5 "ceh'", 1.0 "cis'", -1.0 "ces'", 1.5 "cisih'", -1.5 "ceseh'"}

然后我通过在另一个函数中 geting 映射中的键来获取值。

(defn keynum->name
  ([keynum] (->> 0.0 (get (build-quarter-note-group keynum))))
  ([keynum transposition] (->> (float transposition) (get (build-quarter-note-group keynum)))))

由于键在 keynum->name 函数中都是浮点数,所以我确实尝试进行类型强制转换,但发生了这种情况:

(keynum->name 60 1) ;;=> nil
(get (build-quarter-note-group 60) (float 1)) ;;=> nil

(float 1) 的结果会怎样?

引用给the issue I opened in the Clojure Jira的答案:

我认为在最多 8 个键的映射中查找浮点数这一事实是实现的意外。

使用较大的映射和散列集失败的原因是 (double 1.0) 和 (float 1.0) 的散列值不同。

user=> (hash (float 1.0))
1065353216
user=> (hash 1.0)
1072693248

您示例中的所有值(如 1.0 和其他值)都默认为双精度类型。请注意,如果您强制将地图的键设置为浮动,那么即使地图的键超过 8 个,查找也会成功:

user=> (get {(float 1.0) "a" 2.0 "b" 3.0 "c" 4.0 "d" 5.0 "e" 6.0 "f" 7.0 "g" 8.0 "h" 1 "i"} (float 1)) 
"a"

我的猜测是,除了在 return 成功查找时发生小地图意外之外,这里的一切都按设计工作。

我相信使用小地图 get 确实找到查找匹配项 (float 1) 的原因可能是因为小地图的实现是作为一个 ArrayMap,其中查找键顺序与一个中的所有键进行比较使用 clojure.core/=(或其 Java 等价物)和:

的数组
user=> (= (float 1) (double 1))
true

所以,简而言之 - 地图中的键是双精度而不是浮点数。

(get (build-quarter-note-group 60) (double 1)) => "cis'"