2017-04-21 55 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并且现在发生冲突,那么这是最好也是不可能的。


具有不读的书幽灵如果直接回答原来的问题,我不能说,但你不妨实验一下。除非你有冲突的命名空间/功能问题,否则你应该得到相同的结果。您还可以对您的程序进行配置,以确定其中一个或另一个是否会加速您的程序。

现在仔细看看这段文字,我看不出它应该对他所引用的用例有什么影响。您可以尝试验证答案。