Использование протокола с примитивными аргументами
Я пытаюсь определить протокол в Clojure 1.4 с примитивными аргументами (чтобы я мог избежать ненужного примитивного бокса в чувствительном к производительности коде):
(defprotocol A
(foo [a ^long x]))
(extend-type java.lang.String A
(foo [s ^long x] (.charAt s x)))
Похоже, что это работает нормально, но не удается, за исключением, когда я пытаюсь его использовать:
(foo "abracadarbra" 3)
=> ClassCastException XXXX cannot be cast to clojure.lang.IFn$OLO
Что я делаю неправильно?
2 ответа
Решение
После дальнейших исследований выясняется, что протоколы еще не поддерживают подсказки примитивного типа (начиная с Clojure 1.4). Смотрите, например, https://groups.google.com/d/topic/clojure-dev/HxBqIewc494/discussion
Альтернативы кажутся:
- Написать регулярные функции с примитивными подсказками. Вы теряете полиморфизм.
- Используйте интерфейс Java (вы можете использовать reify для создания экземпляров в Clojure)
Взять подсказку типа из defprotocol
и оставить его в extend-type
(defprotocol A
(foo [a x]))
(extend-type java.lang.String A
(foo [s ^Long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a
или вы можете изменить подсказку типа следующим образом:
(defprotocol A
(foo [a ^Long/TYPE x]))
(extend-type java.lang.String A
(foo [s ^long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a
это все еще не дает никаких отражений предупреждения без намека на defprotocol
РЕДАКТИРОВАТЬ:
(extend-type java.lang.String A
(foo [s ^Long x] (type x)))
nil
core> (foo "abracadarbra" 3)
java.lang.Long