10

プロトコルと、1 つのワークスペース内でそれを実装するいくつかの deftypes があります。次のプロトコルを実装するすべての deftypes を一覧表示するにはどうすればよいですか?

(ns-public)からデータをフィルタリングするソリューションにたどり着きましたが、目標を達成するための適切な方法が見つからなかったため、作業を完了するために「魔法」を使用しているため、好きではありません満足する?そして伸びる?.

何か案は?

(defprotocol Protocol
  (foo[this] "just an interface method"))


(deftype Dummy [] Protocol
  (foo[this] "bar"))


(defn implements? [protocol atype] "fn from clojure sources"
  (and atype (.isAssignableFrom ^Class (:on-interface protocol) atype)))


(defn list-types-implementing[protocol]
  (filter (fn[x] (let [[a b] x]
            (when (.startsWith (str a) "->") ; dark magic        
              (implements? protocol 
               (resolve (symbol 
                (.replace (str a) "->" "")))))
            )) 
         (ns-publics *ns*)))

(list-types-implementing Protocol) ; => ([->Dummy #'user/->Dummy])

(let [[a b] (first(list-types-implementing Protocol))]
    (foo (b)) ; => "bar"
)
4

1 に答える 1

3

一般に、型がプロトコルを満たすには 2 つの異なる方法があるため、これは解決が困難な問題になります。extend-typeand関数を使用して、既存の Java クラスをプロトコルextend-protocolに拡張できます (これは非常に強力な機能です。コードを拡張して、組み込みの Java または Clojure 型、または他のサードパーティの型で動作するようにすることができるからです。) t コントロール)。deftypeまたは、またはの型定義の一部として、プロトコルの実装を直接指定できますdefrecord。これら 2 つのメカニズムは、異なる方法で実装されます。

最初のケース (extend-typeまたはによる拡張extend-protocol) は、拡張される型がプロトコル自体にアタッチされるため、解決が容易になります (プロトコルは基本的に、生成された Java インターフェイスと、プロトコルに関するメタデータを含む Clojure マップになります)。 )。:implsプロトコル マップのキーを調べると、プロトコルを拡張する型を見つけることができます。

user=> (defprotocol MyProtocol (foo [this] "Protocol function"))
user=> (deftype MyType [])
user=> (extend-type MyType MyProtocol (foo [_] "hello foo!"))
user=> (keys (:impls MyProtocol))
(user.MyType)

2 番目のケース (deftypeまたはを介し​​てプロトコルを直接実装するdefrecord) は、型またはレコード用に生成された Java クラスが、プロトコルによって定義された Java インターフェイスを直接実装するため、より困難です (deftypeまたはdefrecordだけでなく、任意の Java インターフェイスを実装できます)。プロトコル)。この方法でプロトコルを拡張する型を見つけるアプローチには、ある程度のスキャンとリフレクションが必要になります。基本的に、あなたが求めているのは、「特定のインターフェースを実装しているすべての Java クラスを見つけるにはどうすればよいですか?」ということです。

典型的な Java アプリケーションでは、クラスパスのディレクトリをスキャンして .class ファイルを探し、それらをイントロスペクトする方法に沿って何かを行うことがありますが、これは Clojure では機能しません。タイプの .class ファイルがない可能性が非常に高いためです(バイトコードは動的に生成されます)。独自の実装に満足できない場合は、この質問の回答をチェックして、好みに合うかどうかを確認してください。

インターフェースを実装する Java クラスを見つける

于 2013-01-10T15:55:00.633 に答える