4

Suppose I define a record called Node: (defrecord Node [tag attributes children]).

After this definition, according to the docstring of defrecord a factory function called ->Node is defined, as well as another factory function map->Node and a Java class constructor Node..

I'm wondering what exactly the difference is between the positional factory function ->Node and the constructor Node., apart from the normal differences between a Java class constructor / method on the one hand and a clojure function on the other (by normal differences I'm thinking things like the fact that functions are first-class in Clojure while methods are not).

4

2 回答 2

8

(更新:有关原始字段类型与ctor的参数类型与工厂的参数类型的注释,请参见此答案的末尾。)

位置工厂只是直接调用构造函数。除此之外唯一有趣的是,对于具有大量字段(即超过 20,这是 Clojure 函数可以接受的位置参数的最大数量)的记录/类型,构造函数调用稍微复杂一些(因为您必须解压缩来自 rest-args seq 的一些参数);位置工厂由发出defrecorddeftype正确处理,此外检查是否提供了正确数量的参数,如果没有则抛出适当的异常。

这记录在私有函数的文档字符串中clojure.core/build-positional-factory(doc clojure.core/build-positional-factory)在 REPL 上说要阅读它,或者(source clojure.core/build-positional-factory)查看源代码。

最终结果大致如下所示:

;; positional factory for a type with up to 20 fields
(defn ->Foo
  "Construct a Foo."
  [x y z]
  (new Foo x y z))

;; positional factory for a type with many fields
(defn ->Bar
  "Construct a Bar."
  [a b c d e f g h i j k l m n o p q r s t & overage]
  (if (= (count overage) 2)
    (new Bar a b c d e f g h i j k l m n o p q r s t
             (nth overage 0) (nth overage 1))
    (throw
     (clojure.lang.ArityException.
      (+ 20 (count overage)) (name '->Bar))))))

关于参数类型的说明:

不确定这是否属于“正常差异”的范畴,所以我会明确提及:deftype/defrecord引入的类可能具有原始类型的字段,在这种情况下,构造函数的相应参数也将是原始类型。然而,从 Clojure 1.5.1 开始,位置工厂总是接受所有Object参数,即使在技术上它们可以被声明为原始接受函数(也就是说,如果所涉及的原始类型是long和/或double并且最多有四个位置工厂参数)。

于 2013-06-09T00:58:27.297 回答
2

#{},空集。除了您明确表示您不感兴趣的差异之外,没有其他差异。->Foo之所以存在,是因为函数比构造函数更友好。

于 2013-06-09T02:47:41.253 回答