2017-04-21 54 views
0

e-book about specter,有這樣一段話:Clojure的擴展型VS DEFTYPE和協議實現

我們需要定義所有的類型是這樣的:

(deftype AllType [])

最後,我們需要添加AllType 執行select *

(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,在最後一章討論了這一點。你不妨在那裏看看更多的細節。

它的要點是它們在概念上看起來相同,但它們不是。 他描述了一個語義「gotcha」,因爲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中,你會試着說

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

所以Clojure中,我可以有一個單一的對象上2種run方法具有相同的名稱&簽名當且僅當我使用extend-protocol。如果我嘗試定義聯機崩潰:

(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就像是試圖哈瓦Java接口有兩個void run()方法。爲了使它工作,你必須將方法名稱改爲myRunyourRun,如果兩個外部庫已經選擇函數名稱run並且現在發生衝突,那麼這是最好也是不可能的。


具有不讀的書幽靈如果直接回答原來的問題,我不能說,但你不妨實驗一下。除非你有衝突的命名空間/功能問題,否則你應該得到相同的結果。您還可以對您的程序進行配置,以確定其中一個或另一個是否會加速您的程序。

現在仔細看看這段文字,我看不出它應該對他所引用的用例有什麼影響。您可以嘗試驗證答案。