在运行时访问 clojure 类型提示



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

(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)

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

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

地图可能如下所示:

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

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

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

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 层将处理实现协议的任何对象。

没有简单的方法可以在运行时访问类型提示。您必须将 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。

最新更新