为什么我不能在clojure中绑定一个defrecord?

时间:2012-04-07 16:01:53

标签: java clojure interop

我有这样的事情:

user> (defrecord vertex [id val]) => user.vertex
user> (def v vertex)              => #'user/v
user> (= v vertex)                => true
user> (type v)                    => java.lang.Class
user> (type vertex)               => java.lang.Class
user> (vertex. 1 2)               => #user.vertex{:id 1, :val 2}
user> (v. 1 2)                    => "Unable to resolve classname v"
user> (new v 1 2)                 => "Unable to resolve classname v"

所以基本上我不能将顶点绑定到另一个名称。尝试将defrecord类型传递给函数,或者让或者其他任何东西都是一样的。 为什么会这样,我该怎么做才能临时重命名一个defrecord?

我猜这是与Java互操作有关的一些技巧。

2 个答案:

答案 0 :(得分:4)

defrecord生成一个Java类,我认为它实际上被视为Clojure中的一种特殊情况,特别是关于互操作(虽然我不是正面的)。

如果你的目标是能够轻松传递一个可以创建顶点的函数,那么解决方案是使用一个调用构造函数的本地函数,而不是自己进行互操作。

在Clojure 1.3中,deftype和defrecord自动生成另外两种方法:

  • ->{type}等同于构造函数
  • map->{type}将参数图作为参数

对于上述情况,(->vertex 1 2)(map->vertex {:id 1 :val 2})有效,并允许您进行后续构建。

如果您确实需要在传递它时可用的类,可能有些东西可以用宏来做,虽然我不确定。

答案 1 :(得分:2)

据我所知,这是不可能的。

如果你考虑defrecord如何运作;它实际上是字节码生成一个(java)类。当您在一个命名空间中执行defrecord并希望在另一个命名空间中使用它时,您可以看到这一点......

(ns my-first-namespace)
(defrecord Foo [x y])

(ns my-second-namespace
   (:use my-first-namespace)
   (:import my_first_namespace Foo)) ; still have to import the java class 
                                     ; underlying the defrecord even tho 
                                     ; the defining namespace is use'd (note 
                                     ; hyphen / underscore changes). 

不幸的是,java(实际上在JVM中)没有办法将类名别名为另一个类名。你可以得到的最接近的是子类化为一个新名称,但这相当粗略。