【问题标题】:What's so hard about equality?平等有什么难的?
【发布时间】:2012-05-31 03:44:50
【问题描述】:

例如,在 Javascript 中,[1,2,3] === [1,2,3][1,2,3] == [1,2,3] 都是 false。即使是更简单的空数组也是错误的。原因是数组是引用类型,[1,2,3][1,2,3] 作为引用是不同的。 Javascript 在这方面并不是独一无二的,几乎每种语言都将相等作为引用相等来实现,除了最基本的类型,如整数,可能还有一些内置类型。

为什么会这样?让默认的相等运算符变得更强大有什么难的?那么,除了比较参考文献之外,为什么还很难比较结构属性呢?

我知道许多语言都提供了将某些运算符重载为其他含义的工具,因此== 将表示您想要的含义,而不是通常的弱引用相等。我的问题不是语言是否提供了这样的功能,而是为什么默认的相等运算符不是更明智的,所以 [1,2,3] == [1,2,3] 默认评估为 true 并且不需要程序员干预。

在 python 中,上面的例子计算结果为真,但如果你定义了下面的类

class A:
  def __init__(self, prop):
    self.prop = prop

然后将a = A(1)b = A(1) 进行比较,那么即使在结构上ab 是相同的并且如果您所知道的只是位模式,则无法区分它们。定义对象。

【问题讨论】:

  • 为什么仅仅因为他们决定以他们的方式实施它就很难做到这一假设?
  • @kinakuta 因为几乎所有的语言都这样做,这表明存在某种障碍。如果这很容易,那么有人会实现一种语言,该语言可以为数组相等和更通用的类型做明显的事情。

标签: types theory equality


【解决方案1】:

并非所有语言都按照您描述的方式工作。例如,在 Python 中,== 是相等,is 是引用比较:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True
>>> a is b
False

【讨论】:

  • 确实如此,但如果我用自己的属性定义自己的自定义类,那么a = Klass(val) 将不等于b = Klass(val)
  • @davidk01:您需要为您的班级实现__eq__ method。这就是== 所说的。
  • 是的。这就是我的观点。有一个默认的 __eq__ 操作符做正确的事情有什么难的。
  • 好吧,我不明白你的意思。在 Python 中,== 确实 为 Python 的内置对象类型(包括数组)做“正确的事”。如果您实现自己的类,那么您有责任定义 == 的含义,如果这对您很重要。
  • 我已经修改了我的答案,以便更清楚地了解我在问什么。比较对象时要做的显而易见的事情是查看所有属性并验证它们在相等运算符的两侧是否相同。只有当程序员想要使用其他形式的相等时,他才必须定义它。如果我在做模运算,那么使用1 == 6 可能是有意义的,在这种情况下,我应该重新定义相等性。您不希望一种语言让您来决定 1 == 6 是真还是假,那么为什么这不适用于自定义类型呢?
【解决方案2】:

并非所有语言都这样做。 C++ 在对象上使用== 表示相等(尽管指针上的== 确实表示引用相等)。我相信(虽然我不完全确定)D 编程语言保留 == 用于值相等和 is 运算符用于引用相等。

我认为这只是 JavaScript 和其他一些语言的设计决定。没有理由必须这样。

【讨论】:

  • 所以在 D 中 [1,2,3] == [1,2,3] 评估为真?
【解决方案3】:

几乎每种语言都将相等作为引用相等来实现

正如这个问题上的types 标签所示,许多语言都将相等作为类型的行为来实现。这是有道理的:大多数类型都有一些属性可以在实例上更改,而不会更改该实例的语义“值”。

所以我给出的答案是:相等并不难,由类型来定义哪些实例相等。在没有这样一个明确的决定的情况下,任何默认值都应该是保守的。

如果您要创建自定义类型,则由您自行决定;如果语言支持继承,用它来表达你的决定“平等应该表现得像其他更基本的类型”。否则,请为该类型显式编写相等测试代码,就像对您认为具有正确行为的现有类型所做的那样。

【讨论】:

    猜你喜欢
    • 2015-11-05
    • 2014-06-04
    • 2023-03-21
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多