2017-04-21 5 views
0

対を、この一節があります:はClojureの拡張型<a href="https://leanpub.com/specter/read#fnref-tailrecursive" rel="nofollow noreferrer">e-book about specter</a>でのDeftypeとプロトコル実装

私たちは、このようなすべてのタイプを定義する必要があります。

(deftype AllType [])

は最後に、私たちのようにする必要がありAllTypeの の実装を選択*

(extend-type AllType Navigator (select* 
[this structure continuation] 
    ...)) 

あなたはプロトコルと堪能している場合は、我々は我々がタイプを定義するとき、SELECT *定義していない理由(あなたが疑問に思うことがあります。

(deftype AllType [] 
    Navigator 
    (select* [this structure continuation] 
    ...)) 

を理由は、特定のプロトコル機能の実装依存のルックアップにはないということですそのように定義された関数のための仕事)。

私は実際にここで言うことを得ようとしていません。 extend-typedeftype +インプレース実装の違いは何ですか?

+1

電子ブックへのリンクが機能しません。 –

+0

@AlanThompsonありがとう、訂正しました。 – nha

+1

"その理由は、特定のプロトコル関数の実装依存のルックアップは、そのように定義された関数では機能しないからです。私には意味がありません。彼らは実装方法が異なりますが、どのような違いが記述されているのかはまったくわかりません。 –

答えて

2

私はちょうど最後の章でこれについて議論するthe Clojure Polymorphism bookを読み終えました。詳細はこちらをご覧ください。

概念の概念は同じであると思われますが、そうではありません。 彼は、Javaクラスも名前空間を定義しているので、意味論的な「つかまり」を記述しています。たとえば:

(ns my.ns) 
(defprotocol Foo (run [this])) 

(ns your.ns) 
(defprotocol Foo (run [this])) 

(ns user) 
(defrecord FooAble []) 
(extend-protocol my.ns/Foo 
    FooAble 
    (run [this] (println "Foo Me"))) 
(extend-protocol your.ns/Foo 
    FooAble 
    (run [this] (println "Foo You"))) 

(println 1 (->FooAble)) 
(def some-foo (->FooAble)) 

(my.ns/run some-foo) => Foo Me 
(your.ns/run some-foo) => Foo You 

Javaでは、あなたは、私がextend-protocolを使用する場合に限っ

someFoo.run() => Which `run` method...? 

だからClojureの中に、私は単一のオブジェクトで同じ名前&シグネチャを持つ2つの runメソッドを持つことができると言うしようとするだろう。私はインラインで定義しようとした場合には、クラッシュ:

(defrecord BeerAble [] 
    my.ns/Beer 
    (run [this] (println "Beer Me")) 
    your.ns/Beer 
    (run [this] (println "Beer You"))) 

(println 2 (->BeerAble)) 
(def some-beer (->BeerAble)) 

(my.ns/run some-beer) 
(your.ns/run some-beer) 

;=> CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file user/BeerAble, 

だから、インラインdefinnitionが2つのvoid run()方法でJavaインタフェースをHAVAしようとしているようなものです。それを動作させるには、メソッド名をmyRunyourRunに変更する必要があります.2つの外部ライブラリがすでに関数名runを選択していて、今クラッシュしている場合は不可能です。


Specterの本を読んでいないと、これは元の質問に直接答えることはできませんが、ちょっと試してみることもできます。クラッシュする名前空間/関数の問題がない限り、どちらの場合でも同じ結果が得られるはずです。また、あなたのプログラムをプロファイリングして、あなたのプログラムのスピードアップを判断することもできます。

より詳しくは、彼が引用したユースケースには違いがあるはずがありません。あなたは答えを検証するために実験をすることができます。

関連する問題

 関連する問題