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 に答える