3

假设我定义了一个包含一些类型提示的记录,如下所示:

(defrecord person [name sex ^Integer age city])

有没有办法在运行时使用person类或实例来确定指定了哪些类型提示person?目的是根据字段的类型改变使用的gui组件(注意字段的值可能是nil,所以我不能用值的类型来确定字段的类型)。

我尝试了一些明显的事情,但没有得到任何地方:

; no metadata on the class, an instance, or the keys or vals of an instance
=> (meta person)
nil
=> (meta (person. "Geoff" "male" 30 "Moon base"))
nil
=> (map meta (keys (person. "Geoff" "male" 30 "Moon base")))
(nil nil nil nil)
=> (map meta (vals (person. "Geoff" "male" 30 "Moon base")))
(nil nil nil nil)
; the field is of type Object
=> (filter (fn [x] (= "age" (.getName x))) (.getFields person))
(#<Field public final java.lang.Object matt.clarity.scratch.person.age>)
; no metadata on the fields of the class
=> (map meta (.getFields person))
(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)
4

3 回答 3

3

我认为你应该从不同的角度来处理这个问题:

  • 创建一个定义字段和数据类型的地图
  • 使用此映射生成适当的 defrecord 和任何查看器/属性编辑器

该地图可能类似于:

  {:name java.lang.String
   :sex  java.lang.String
   :age  java.lang.Integer}

然后,此地图将用作驱动系统其余部分的元数据......

于 2012-07-04T11:38:24.577 回答
2

似乎在记录字段上应用类型提示对反射没有任何影响,因此它们被忽略了。

user=> (set! *warn-on-reflection* true)
user=> (defrecord user [^String name])     
user=> (.indexOf "z" (:name (user. "Superman")))
Reflection warning, NO_SOURCE_PATH:16 - call to indexOf can't be resolved.
-1

此外,我不建议对与您的业务逻辑相关的内容使用类型提示,我更愿意使用我自己的数据标签来描述要在 UI 控件中显示的数据类型。可以定义一个协议,该协议具有获取特定类型字段类型的方法,然后在定义记录时在您的记录上实现该协议。

就像是:

user=> (defprotocol DescribeData (getFieldTypes [this]))
user=> (defrecord User [name age] DescribeData (getFieldTypes [_] {:name String :age Integer}))
user=> (def u (User. "Superman" 1000))
user=> (getFieldTypes u)
{:name java.lang.String, :age java.lang.Integer}

这样,您可以将任何对象传递给 UI 层,并且 UI 层将与任何实现该协议的对象一起使用。

于 2012-07-04T11:33:43.710 回答
1

没有简单的方法可以在运行时访问类型提示。您必须将 defrecord 包装在您自己的宏中,该宏可以访问如下提示:

(->> (-> '(defrecord Foo [^Integer a b c]) 
         macroexpand-1
         (nth 2)
         (nth 3))
     (drop-last 2)
     (map #(vec [% (-> % meta :tag)]))) ; => ([a Integer] [b nil] [c nil])

但是,我宁愿建议使用@mikera 的答案并构建一个宏,该宏发出一个defrecord 和一个包含字段-> 类型映射的defvar。

于 2012-07-04T12:53:44.477 回答