Как работает определение имени метода defjord в clojure? - PullRequest
14 голосов
/ 29 января 2011

После определения записи и интерфейсов, которые она реализует, я могу вызывать ее методы либо по ее имени, либо используя способ взаимодействия java с помощью оператора точки.

 user=> (defprotocol Eat (eat [this]))
 Eat
 user=> (defrecord animal [name] Eat (eat [this] "eating"))
 user.animal
 user=> (eat (animal. "bob"))
 "eating"
 user=> (.eat (animal. "bob"))
 "eating"
 user=> 

Что под поверхностью, что там происходит? Определены ли новые функции clojure? Что происходит, когда есть определенные вами функции с одинаковыми именами (возможно ли это?), Как разрешаются эти неоднозначности?

Кроме того, возможно ли "импортировать" методы java для других объектов java, так что вам не нужно. оператор, чтобы поведение было как выше? (Например, для унификации пользовательского интерфейса)

1 Ответ

23 голосов
/ 30 января 2011

Когда вы определяете протокол, каждый из его методов создается как функции в ваших текущих пространствах имен.Следовательно, вы не можете иметь два протокола, определяющих одну и ту же функцию в одном и том же пространстве имен.Это также означает, что вы можете иметь их в отдельных пространствах имен и что данный тип может расширять оба [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-*) из-за ограничения реализации

...