Я пишу свой собственный range
, который реализует ISeq
.Моя первоначальная реализация для equiv
просто вызывала seq
в моем диапазоне и другом списке и сравнивала с использованием =
:
(defn equals? [this-range other-range]
(= (seq this-range) (seq other-range)))
Это казалось нормальным, но затем я столкнулся с некоторым странным поведением:
(= (new-range 5 10)
(range 5 10))
=> true
(= (range 5 10)
(new-range 5 10))
=> false ; Uh oh
Где new-range
- мой пользовательский конструктор.
Чтобы увидеть, как LongRange
обрабатывает эквивалентность, я проверил его источник.Он делегирует ASeq
, и метод ASeq
equiv
начинается со строк:
public boolean equiv(Object obj) {
if (!(obj instanceof Sequential) && !(obj instanceof List)) {
return false;
. . .
Поскольку мой диапазон не реализует Sequential
или List
, эта проверка завершается неудачно.Он даже не пытается перебрать мой диапазон для сравнения значений.
В чем здесь причина?Sequential
это просто пустой интерфейс.Кажется, он просто существует, чтобы «помечать» классы как последовательные, не требуя каких-либо методов.
Я мог бы просто реализовать свой диапазон Sequential
, чтобы разрешить проверку, но мне интересно, должна ли моя функция эквивалентности включатьтакая же проверка, как и ASeq
.Это кажется ненужной проверкой, так как seq
уже потерпит неудачу при неверном аргументе через clojure.lang.RT/seqFrom
.
Какова цель проверки Sequential
, если я должен реализовать Sequential
, чтобы успокоить такоеметоды, и я должен сделать такую проверку в аналогичных методах?