Когда вы определяете протокол, каждый из его методов создается как функции в ваших текущих пространствах имен.Следовательно, вы не можете иметь два протокола, определяющих одну и ту же функцию в одном и том же пространстве имен.Это также означает, что вы можете иметь их в отдельных пространствах имен и что данный тип может расширять оба [1] из них без какой-либо вставки имен, поскольку они имеют пространство имен (в отличие от Java, где один класс не может реализовать два интерфейса с одноименными методами).
С точки зрения пользователя, методы протокола ничем не отличаются от простых старых неполиморфных функций.
Тот факт, что вы можете вызывать метод протокола с помощью взаимодействия, является деталью реализации.Причина в том, что для каждого протокола компилятор Clojure создает соответствующий интерфейс поддержки.Позже, когда вы определите новый тип с внутренними расширениями протокола, этот тип будет реализовывать интерфейсы поддержки этих протоколов.
Следовательно, вы не можете использовать форму взаимодействия для объекта, для которого расширение не былопри условии: inline:
(defrecord VacuumCleaner [brand model]
(extend-protocol Eat
VacuumCleaner
(eat [this] "eating legos and socks"))
(.eat (VaacumCleaner. "Dyson" "DC-20"))
; method not found exception
Компилятор имеет специальную поддержку функций протокола, поэтому они компилируются как проверка экземпляра с последующим вызовом виртуального метода, поэтому, когда это применимо, (eat ...)
будет так же быстро, как (.eat ...)
.
Чтобы ответить на вопрос «можно ли импортировать java методы», вы можете заключить их в обычные fns:
(def callme #(.callme %1 %2 %3))
(очевидно, вам может понадобиться добавить другие аргументы для учета перегрузок и подсказок типовчтобы удалить отражение)
[1], однако вы не можете расширить оба inline (по крайней мере один из них должен быть в форме extend-*
) из-за ограничения реализации