我正在编写自己的 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
只是一个空接口 . 它似乎只是存在于"mark"类中,而不需要任何方法 .
我可以让我的范围实现 Sequential
以允许检查,但我想知道我的等价函数是否应该包括与 ASeq
相同的检查 . 这似乎是一个不必要的检查,因为 seq
将通过 clojure.lang.RT/seqFrom
在一个错误的参数上失败 .
Sequential
检查的目的是什么,我应该实现 Sequential
来安抚这些方法,我应该在类似的方法中进行这样的检查吗?
1 回答
你希望获得什么样的回报 Value
或来自
?在这两种情况下,两个集合在它们之后都是无法区分的(取决于
#{1 2}
如何得到哈希值) . 但它们显然不是相同的集合:映射和集合与列表和向量的行为非常不同 . 区分每一对的主要因素是其中一个是Sequential(打算以顺序方式使用)而另一个不是 . 这就是这个标记界面的用途 .所以,是的,你应该在声明顺序对象等于某个其他对象之前检查Sequential:它不能合理地等于任何非顺序对象 .