Pharo Smalltalk中=和==的区别是什么?

5
在Pharo Smalltalk中,“=”和“==”有什么区别?它们的名称分别为“isEqual”和其他什么?
= ~=    equality / inequality (deep)
== ~~   equality / inequality (shallow)

5
= 表示“相等”(两个对象的值相等),== 表示“恒等”(两个对象完全相同)。详见《Equality versus Identity》 - lurker
3个回答

5
重要的一点是,= 不仅在代码显式比较两个对象时使用。许多其他消息也会隐式使用消息 =,例如:includes:<=>=remove:keyAtValue:indexOf:upTo:peekFor:occurrencesOf:add:(在Set中)、at:(和朋友们at:ifAbsent:at:ifAbsentPut:等)以及其他许多消息。

这意味着,当您重新定义类中的=时,您应该确保:

  1. 您对=的实现是强大的(例如,banana = car不会出错),并且
  2. 每次您重新定义=时,您也需要重新定义hash

第一个条件的原因是为了能够比较任何两个对象,而不需要发送方在发送=消息之前进行特殊处理。

第二个条件的原因是,如果将来您的对象在散列集合(SetDictionaryBag等)中使用,它们将遵守这些实体所需的重要不变量。

      IF a = b THEN a hash = b hash

考虑到确保 hash 值是SmallIntegers 是一个非常好的实践,可以这样说:

      IF a = b THEN a hash == b hash

换句话说,每当两个对象被认为是“相等”的时候,它们的哈希值应该被授予为“相同”。
命名 在读取涉及“=”的表达式(如a=b)时,可以说a“等于”b或a“等于”b。
当读取a==b时,Smalltalkers会说a“和”b“是同一个对象”,或者a“等同于”b,甚至是a“等于等于”b。 进一步评论 “=”消息是特定于领域的,这意味着由您决定在应用程序中何时表示两个Smalltalk对象代表完全相同的对象。
“==”消息是系统功能,这意味着它是由虚拟机(VM)实现的,该虚拟机验证正在比较的对象是否占据内存中的完全相同位置。换句话说,当两个变量a和b绑定到完全相同的对象时,它们是“相等的”。 例子
a := 'This String'.
b := 'This' , ' ', 'String'.
a == b "false".
a = b "true"

f := 2 / 3.
g := 2 / 3.
f = g "true".
f == g "false"

通常情况下,SmallInteger类型的值如果使用=运算符进行比较,同时也会使用==运算符,因为虚拟机以一种特殊的方式对它们进行编码。

n := 3 + 4.
m := 2 + 5.
n = m "true".
n == m "true".

另一个有趣的情况出现在Symbol类的实例中。

s := #symbol.
t := 'symbol' asSymbol.
s = t "true".
s == t "true!"

这是由于Symbol类确保在环境中永远不存在具有相同底层字符串的两个实例。

命名方面怎么样?是用“等于”、“同于”还是“恰好等于”? - unom
1
@unmircea中的=表示“等于”或“具有相同的值”。==表示“完全相同”或“是同一对象”。 - lurker

4

是的,== 是身份运算符,它使用原始类型来比较指针是否指向相同地址(即相同对象)。

= 是相等运算符,意思是两个对象相等,尽管它们可能是两个不同的对象。默认情况下,= 使用 == ,但它可以重新实现。此外,当您重新实现 = 时,建议还重新实现 hash,以便散列集合不会出错。


命名方面怎么样?是用“等于”、“同于”还是“恰好等于”? - unom
@unmircea 我认为它们是相等和相同的,但通常我使用“相等”,对于 == 我会说:_检查它是否是同一对象_。 - Uko

1
TL;DR: = : "等于", == : "与...相同"
在对象中,#=代表的是等于号。
= anObject 
"Answer whether the receiver and the argument represent the same 
object. If = is redefined in any subclass, consider also redefining the 
message hash."

^self == anObject 

在ProtoObject类中的#==方法
#==方法用于判断接收者和参数是否是同一个对象(有相同的对象指针)。这是一个原语方法,不应该在任何其他类中重新定义#==消息。它是必需的,并且不能在任何子类中重写。请参阅Object文档中的whatIsAPrimitive。
<primitive: 110>
self primitiveFailed

所以,你可以重写=但不能重写==。
FWIW ProtoObject subclass:# Object 一个# =重写的例子是
´= aBag “如果两个袋子(a)是同一种东西, (b)它们的大小相同。 (c)每个元素在它们两者中都出现相同的次数,则它们相等。”
(aBag isKindOf: Bag) ifFalse: [^false].
self size = aBag size ifFalse: [^false].
contents associationsDo: [:assoc|
    (aBag occurrencesOf: assoc key) = assoc value
        ifFalse: [^false]].
^true`

Dictionary 相比,它是一种完全不同的实现(Bas 在“有趣”方面实现了它)。
`Dictionary>>#= aDictionary “如果两个字典 (a)是同一种类型的东西。 (b)拥有相同的键集。 (c)对于每个(共同的)键,它们具有相同的值。 请在更改之前查看问题16760。”
self == aDictionary ifTrue: [^true].
self species == aDictionary species ifFalse: [^false].
self size = aDictionary size ifFalse: [^false].
self associationsDo: [:assoc|
    (aDictionary at: assoc key ifAbsent: [^false]) = assoc value
        ifFalse: [^false]].
^true`

有趣的是它们共享相同的哈希方法。

`Collection>>#hash "返回接收器的整数哈希值,使得, -- 未更改对象的哈希值随时间保持不变,且 -- 两个相等的对象具有相等的哈希值"

| hash |

hash := self species hash.
self size <= 10 ifTrue:
    [self do: [:elem | hash := hash bitXor: elem hash]].
^hash bitXor: self size hash

当自身大小<=10时,会有一些气味,尝试跟踪这些调用。

更多基本对象,请参见以下内容:

Magnitude>>#hash implementers

祝您探索愉快。

在Spotter中,hash #im= #im会给出实现者列表,因此您可以快速了解它们。

enter image description here


2
请注意,基于xor的哈希通常不是最优的,因为它们不使用比被xor的元素中更高阶位的位。 - Leandro Caniglia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接