如何将协议一般地扩展到ClojureScript集合



如果您尝试运行以下代码,您会看到它将进行编译,但在运行时的倒数第二行由于"没有为类型cljs.core/PersistentArrayMap:{}定义协议方法NameSayer.say-name"而失败,即使它满足?调用返回true。IVector/PersistentVector情况也会出现类似的故障,尽管也满足所需的协议。

(defprotocol NameSayer
  (say-name [input]))
(extend-protocol NameSayer
  number
  (say-name [_]
    "I'm a number!")
  string
  (say-name [_]
    "I'm a string!")
  IMap
  (say-name [_]
    "I'm a map!")
  IVector
  (say-name [_]
    "I'm a vector!"))
(println (satisfies? IMap {}))
(println (satisfies? IVector []))
(println (say-name "hello"))
(println (say-name 100))
(println (say-name {}]))
(println (say-name []))

我在clojuescription.core中窥探了一下,发现对于像IPrintWithWriter这样的东西,PersistentArrayMap、PersistentHashMap和PersistentTreeMap的实现只是重复的,尽管它们都有通用的IMap接口。有没有比使用协议进行代码复制更好的方法来解决这个问题?

来自clojurians线程的关于同一主题的一些建议:

如果你控制协议-采取协议中的每一种方法,并将其从一种方法更改为另一种方法*

(defn method [o]
  (cond
    (satisfies? Proto o) 
    (method* o)
    (map? o)
    (map-impl o)
    (set? o)
    (set-impl o)
    (sequential? o)
    (sequential-impl o)
    :else
    (throw (ex-info "" {})))

如果性能对于您自己的协议来说不是很重要,那么您也可以通过default进行即default+satisifes?