Programming Clojure学习笔记——多重方法

来源:互联网 发布:萧何和萧何知乎 编辑:程序博客网 时间:2024/05/09 00:19
8.3 超越简单的分发
定义一个打印集合的方法实现:
(use '[clojure.contrib.str-utils :only (str-join)])
(defmethod my-print java.util.Collection [c]
     (.write *out* "(")
     (.write *out* (str-join " " c))
     (.write *out* ")”))
尝试打印各种序列:
(my-println (take 6 (cycle [1 2 3])))
输出:(1 2 3 1 2 3)
(my-println [1 2 3])
输出:(1 2 3)

该方法很好,但打印向量时,不能像向量的定义那样,用方括号将输出包围。因此需要在添加一个实现方法,因为所有向量都实现IPersistentVector,因此可以这样定义该实现方法:
(defmethod my-print clojure.lang.IPersistentVector [c]
     (.write *out* "[")
     (.write *out* (str-join " " c))
     (.write *out* "]"))
但是它不能正常工作,而是抛出异常:
(my-println [1 2 3])
java.lang.IllegalArgumentException: Multiplemethodsmatch
dispatch value: class clojure.lang.LazilyPersistentVector->
interface clojure.lang.IPersistentVectorand
interface java.util.Collection,
and neither ispreferred
问题是现在有两个dispatch值与向量匹配,Collection和IPersistentVector。很多语言限制方法分发来保证这种冲突不会出现,如禁止多继承。Clojure采用一种不同的方法来处理,允许出现冲突,然后通过prefer-method来解决:
(prefer-method multi-name loved-dispatch dissed-dispatch)
当你调用prefer-method的时候,你在告诉它匹配loved-dispatch值胜过dissed-dispatch值,不管是否有冲突。

因此针对上面的问题,我们可以告诉多重方法my-print你更喜欢IPersistentVector:
(prefer-method my-print clojue.lang.IPersistentVector java.util.Collection)
这时,你可以得到你想要的结果了:
(my-println (take 6 (cycle [1 2 3])))
输出:(1 2 3 1 2 3)
(my-println [1 2 3])
输出: [1 2 3]