clojure.core/compare是如何实现java.util.Comparator的?

How does clojure.core/compare implement java.util.Comparator?

我最近在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.Comparatorcompare 看起来像这样:

(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函数吗?

更新:以下是我根据我对被问问题的困惑的回答:我认为问题是关于 3-arity重载而不是 2 元重载。


我认为混淆来自短语 "the two argument version of sort-by passes clojure.core/compare to it"。那是不对的。来看代码:

(. comp (compare (keyfn x) (keyfn y)))

它使用 "dot special form"(请参阅 . 作为列表的第一个元素)。它在这里用作方法调用。它将使用参数 (keyfn x) (keyfn y) 在由 comp 表示的实例上调用方法 compareclojure.core/compare 与这里无关。从 the various forms of dot expressions 开始,这符合以下情况:

(. instance-expr (method-symbol args*))

关于类型提示:这只是一种性能优化,以避免在该方法调用中发生反射。

来自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。