7

看看我正在构建的这个简单的类,作为存储字符串匹配算法结果的基础:

/** Match of a single pattern in full to a single text. */
class Match {
    uint Tpos;

    this(in uint Tpos) { this.Tpos = Tpos; }

    override string toString() {
        return text("Match: Text@",Tpos);
    }
}

这就是事情变得奇怪的地方:

auto m1 = new Match(1), m2 = new Match(1);
writeln(m1.toHash());
writeln(m2.toHash());
writeln(m1 == m2);

印刷

4464528
4464512
false

我看不出为什么默认情况下这两个对象不应该被认为是相等的。我想我可以编写一个自定义toHash()opEquals()函数,但这似乎有点矫枉过正。根据 Andrei Alexandrescu关于 D 编程语言的(好书!),“默认情况下,哈希是通过使用对象的按位表示来计算的。” 有什么想法吗?

4

3 回答 3

8

您必须自己实施toHash,因为Object.toHash取决于地址。如果我没记错的话,它只是一个return cast(hash_t)cast(void*)this.

编辑:是的,我没记错:https ://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L88

于 2012-08-23T19:26:20.760 回答
8

从源代码(dmd2/src/druntime/src/object_.d):

class Object
{
/* snip */
    /**
     * Compute hash function for Object.
     */
    hash_t toHash() @trusted nothrow
    {   
        // BUG: this prevents a compacting GC from working, needs to be fixed
        return cast(hash_t)cast(void*)this;
    }
/* snip */
    /**
     * Returns !=0 if this object does have the same contents as obj.
     */
    equals_t opEquals(Object o)
    {
        return this is o;
    }
}

所以答案很简单,这就是代码的编写方式——他们进行身份检查而不是内容检查。为什么会这样?我真的不知道,但我的猜测是最初编写起来很简单,并且运行良好,以至于没有人费心回到它并更改它。

在新闻组上,有一些关于从 Object 中完全删除这些函数的讨论,所以如果你想要 == 在你的类上,你必须实现一些东西。但是当涉及到这样的事情时,新闻组谈话变成行动所需的时间通常很长。他们可能会改变主意。

目前和可能在可预见的将来使用类相等的最佳方法是在类中编写自己的 opEquals 方法。

于 2012-08-23T19:29:43.070 回答
4

答案很简单:默认情况下,opEqualsfor objects 比较对象的地址。如果您想要值语义(或仅使用 a ) ,则必须覆盖它。struct

旁注:您的使用in不正确。inscope constwhere的缩写,scope意思是“我不会在我的堆栈框架之外转义这个参数”(你可以通过将它分配给一个类字段来做到这一点)。不幸的是,编译器尚未强制执行此操作,这就是您没有收到错误的原因。

于 2012-08-23T19:25:22.380 回答