2011-01-29 4 views
14

レコードとそれが実装するインタフェースを定義した後、そのメソッドをその名前で呼び出すか、ドット演算子を使ってjava interopの方法で呼び出すことができます。表面の下clojureのdefrecordメソッドの名前解決はどのように機能しますか?

user=> (defprotocol Eat (eat [this])) 
Eat 
user=> (defrecord animal [name] Eat (eat [this] "eating")) 
user.animal 
user=> (eat (animal. "bob")) 
"eating" 
user=> (.eat (animal. "bob")) 
"eating" 
user=> 

、何が起こっているの?新しいclojure関数が定義されていますか?同じ名前を共有する関数を定義した場合(これは可能でしょうか?)、これらのあいまいさはどのように解決されますか?

また、他のjavaオブジェクトのjavaメソッドを "インポート"することも可能です。演算子は、上記のような動作ですか?

+0

マイ文体の好みは、Javaのintを回避することですレコード(コンストラクター)とプロトコル(呼び出し)の両方に対するeropフォーム。この場合:(食べ物( - >動物 "ボブ")) –

答えて

23

プロトコルを定義すると、それぞれのメソッドは現在の名前空間の関数として作成されます。同じ名前空間で同じ関数を定義する2つのプロトコルを持つことはできません。また、別の名前空間にそれらを持たせることができます。また、指定された型は名前空間を持たないため、(1つのクラスが同名のメソッドで2つのインタフェースを実装できないJavaとは反対に) 。

ユーザーの観点から見ると、プロトコルメソッドは単純な古い非多型関数と変わりません。

interopを使用してプロトコルメソッドを呼び出すことができるということは実装の詳細です。その理由は、各プロトコルに対して、Clojureコンパイラが対応するバッキングインタフェースを作成するからです。後でインラインプロトコル拡張を使用して新しいタイプを定義するとき、このタイプはこれらのプロトコルのバッキングインターフェースを実装します。

インラインしたがってあなたは拡張子が提供されていないため、オブジェクトに相互運用フォームを使用することはできません。彼らはインスタンスチェックとしてコンパイルされているので、コンパイラはプロトコル機能のための特別なサポートを持っている

(defrecord VacuumCleaner [brand model] 
(extend-protocol Eat 
    VacuumCleaner 
    (eat [this] "eating legos and socks")) 

(.eat (VaacumCleaner. "Dyson" "DC-20")) 
; method not found exception 

それに続いて仮想メソッド呼び出しがあるため、適用可能な場合(eat ...)(.eat ...)と同じくらい速くなります。 「缶1つのインポートJavaメソッド」に返信する

、あなたは、通常のFNSでそれらをラップすることができます:

(def callme #(.callme %1 %2 %3)) 

(明らかにあなたは反射を取り除くために過負荷とタイプのヒントを考慮して他のアリティを追加する必要があります)

[1]両方のインラインを(それらの少なくとも1つは、extend-*形態でなければならない)拡張することはできませんしかし、実装制限の

+0

ありがとう、それは多くをクリアします。 – bmillare

関連する問題