clojure.core/compare 是如何实现 java.util.Comparator 的?
Posted
技术标签:
【中文标题】clojure.core/compare 是如何实现 java.util.Comparator 的?【英文标题】:How does clojure.core/compare implement java.util.Comparator? 【发布时间】:2015-10-06 09:09:31 【问题描述】:我最近在 clojure.core 中看到了这段代码。
(defn sort-by
"Returns a sorted sequence of the items in coll, where the sort
order is determined by comparing (keyfn item). If no comparator is
supplied, uses compare. comparator must implement
java.util.Comparator. If coll is a Java array, it will be modified.
To avoid this, sort a copy of the array."
:added "1.0"
:static true
([keyfn coll]
(sort-by keyfn compare coll))
([keyfn ^java.util.Comparator comp coll]
(sort (fn [x y] (. comp (compare (keyfn x) (keyfn y)))) coll)))
在参数comp
上有一个Comparator
类型提示。但是sort-by
的两个参数版本将clojure.core/compare
传递给它。这是如何运作的?
更新:
我想知道clojure.core/compare
是如何实现java.util.Comparator
的。 compare
看起来像这样:
(defn compare
"Comparator. Returns a negative number, zero, or a positive number
when x is logically 'less than', 'equal to', or 'greater than'
y. Same as Java x.compareTo(y) except it also works for nil, and
compares numbers and collections in a type-independent manner. x
must implement Comparable"
:inline (fn [x y] `(. clojure.lang.Util compare ~x ~y))
:added "1.0"
[x y] (. clojure.lang.Util (compare x y)))
这不只是一个普通的clojure函数吗?
【问题讨论】:
究竟是如何工作的?compare
实现 java.util.Comparator
。您是在问 (a) 它是如何做到的吗? (b) 2-ary 和 3-ary 定义如何工作? (c) 类型提示有什么帮助? (d) sort-by
函数本身在三元情况下如何工作? (e) 别的什么?
我扩展了我的问题。它是 (a)。
将标题调整为针对实际问题。
【参考方案1】:
来自jvm/clojure/lang/AFunction.java
:
public abstract class AFunction extends AFn implements IObj, Comparator, Fn, Serializable
/* ...omitted... */
public int compare(Object o1, Object o2)
Object o = invoke(o1, o2);
if(o instanceof Boolean)
if(RT.booleanCast(o))
return -1;
return RT.booleanCast(invoke(o2,o1))? 1 : 0;
Number n = (Number) o;
return n.intValue();
当 Clojure 编译器编译函数时,它要么将它们实现为 RestFn(如果是可变参数)或 AFunction(否则)的衍生物;但是,RestFn 扩展了 AFunction,所以它都在同一个地方结束。
所以:所有 Clojure 函数都通过 AFunction 直接或间接实现 Comparator。
【讨论】:
【参考方案2】:更新:以下是我基于我的困惑对所问问题的回答:我认为问题是关于 3-arity 重载而不是 2-arity 重载.
我认为混淆来自“sort-by 的两个参数版本将clojure.core/compare
传递给它”这句话。那是不对的。我们来看代码:
(. comp (compare (keyfn x) (keyfn y)))
它使用“点特殊形式”(参见.
作为列表的第一个元素)。它在这里被用作方法调用。它将在comp
表示的实例上调用compare
方法,参数为(keyfn x) (keyfn y)
。 clojure.core/compare
与此无关。从the various forms of dot expressions,这匹配以下情况:
(. instance-expr (method-symbol args*))
关于类型提示:它只是为了避免在该方法调用中反射而进行的性能优化。
【讨论】:
是的,没错,但是当我调用(sort-by key-fn coll)
(两个参数版本)时,它会委托给(sort-by key-fn compare coll)
。传递给三参数版本的compare
也不是clojure.core
中定义的函数吗?
所调用的是 2-arity 重载中 clojure.core/compare 函数上的 compare 方法,所以你说它没有任何关系的说法是不真实的。 - @Finn 我相信你的观察是正确的。
是的,我的错,我误读了这个问题,并认为它与 3 元重载有关。我会编辑我的答案
添加了对此答案的更新。正确答案是查尔斯·达菲的答案。我保留这个是因为我不确定删除答案的礼仪,而且我认为它有有用的信息(不过对于不同的问题)
因为这个答案可以说为网站增加了价值,我认为你不删除它是正确的:事实上它不是不正确的;这简直是离题 - 但其他人发现它很有趣并获得了支持。以上是关于clojure.core/compare 是如何实现 java.util.Comparator 的?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用来自 GRUB 的实模式 BIOS / VESA 调用?