为什么D中默认这些对象不相等?

时间:2012-08-23 19:21:30

标签: object hash d equals

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

/** 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编程语言的book(好书!),“默认情况下,哈希是通过使用对象的按位表示来计算的。”那里有什么想法吗?

3 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分: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方法。

答案 2 :(得分:4)

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

附注:您对in的使用不正确。 inscope const的缩写,其中scope表示“我不会在我的堆栈帧之外转义此参数”(您可以通过将其分配给类字段来实现)。不幸的是,编译器还没有强制执行此操作,这就是您没有收到错误的原因。