我正在写自己的range实现ISeq.我最初的实现equiv只是调用seq我的范围和另一个列表,并使用=以下方法进行比较:
(defn equals? [this-range other-range]
(= (seq this-range) (seq other-range)))
Run Code Online (Sandbox Code Playgroud)
这似乎很好,但后来我遇到了一些奇怪的行为:
(= (new-range 5 10)
(range 5 10))
=> true
(= (range 5 10)
(new-range 5 10))
=> false ; Uh oh
Run Code Online (Sandbox Code Playgroud)
new-range我的自定义构造函数在哪里.
为了了解LongRange句柄的等效性,我检查了它的来源.它代表们ASeq,和ASeq的equiv方法开始与线:
public boolean equiv(Object obj) {
if (!(obj instanceof Sequential) && !(obj instanceof List)) {
return false;
. . .
Run Code Online (Sandbox Code Playgroud)
由于我的范围没有实现,Sequential或者List此检查失败.它甚至没有尝试迭代我的范围来进行值比较.
这是什么原因?Sequential只是一个空的界面.似乎只是存在将类"标记"为顺序而不需要任何方法.
我可以让我的范围工具Sequential允许检查,但我想知道我的等效功能是否应该包括相同的检查ASeq.这似乎是一个不必要的检查,因为seq已经失败了一个坏的论点通过clojure.lang.RT/seqFrom.
Sequential检查的目的是什么,我应该实施Sequential以安抚这些方法,我应该在类似的方法中进行这样的检查吗?
您希望从中获得什么返回值
(= [1 2] #{1 2})
Run Code Online (Sandbox Code Playgroud)
或来自
(= '([1 2]) {1 2})
Run Code Online (Sandbox Code Playgroud)
?在这两种情况下,这两个集合在你使用seq它们之后是无法区分的(无论如何,这取决于#{1 2}散列的方式)。但它们显然不是相等的集合:映射和集合的行为与列表和向量非常不同。每一对的主要区别在于,其中一个是顺序的(旨在以顺序方式使用),而另一个则不是。这就是这个标签接口的用途。
所以,是的,在声明顺序对象等于其他对象之前,您应该检查 Sequential:它不能合理地等于任何非顺序对象。
| 归档时间: |
|
| 查看次数: |
63 次 |
| 最近记录: |