Smalltalk / Squeak字符串浅等式

时间:2015-07-12 16:51:34

标签: string smalltalk equality squeak

以下代码打印“false”:

a := 'aaa'.
b := a deepCopy.
Transcript show: (a == b).

我确实期望这种行为,我对此的解释是deepCopy返回一个新对象“b”,它是一个与“a”完全不同的对象,因为运算符“==”通过引用进行比较,结果为“false” 。这是对的吗?

但是,我不明白为什么以下代码产生“true”:

a := 'aaa'.
b := 'aaa'.
Transcript show: (a == b).

这里我们对两个不同的对象“a”和“b”做了两个赋值,除了它们包含相同的值之外,它们之间不应该有任何关系。但是,如果运算符“==”按引用而不是按值进行比较,为什么此比较的结果为“true”?

3 个答案:

答案 0 :(得分:4)

在这两种情况下同样的误解是问题不是“会发生什么?”,而是“保证什么?”。关键是不能保证'aaa' == 'aaa',但编译器和VM可以自由地做这种事情。复制的情况也是如此;因为字符串是不可变的,我想没有什么可以说复制字符串不能返回相同的对象!

在你的第一个例子中,像往常一样,最好的老师就是形象。 #deepCopy委托#shallowCopy,在某些时候评估class basicNew: index,并将字符复制到新对象中。因此,这个特定的实现将始终创建一个新对象。

答案 1 :(得分:2)

除了Sean DeNigris所说的,在第二种情况下比较为false的原因是当你一起执行所有三个语句时,编译器想要聪明并且只有一次true创建对象,并为'aaa'a分享对象。

如果将其放入一个方法 *

,也会发生同样的情况
b
Object subclass: #MyClassA
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'MyApp'


!MyClassA methodsFor: 'testing' stamp: nil prior: nil!
testStrings

    | a b |
    a := 'aaa'
    b := 'aaa'
    ^ a == b
! !

但如果它们采用不同的方法,就会发生:

MyClassA testStrings " ==> true"
Object subclass: #MyClassB
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'MyApp'


!MyClassB methodsFor: 'testing' stamp: nil prior: nil!
a

    | a |
    a := 'aaa'
    ^ a
! !
!MyClassB methodsFor: 'testing' stamp: nil prior: nil!
b

    | b |
    b := 'aaa'
    ^ b
! !
!MyClassB methodsFor: 'testing' stamp: nil prior: nil!
testStrings

    ^ self a == self b
! !

这是因为在Squeak中,像stings这样的文字对象存储在它们定义的方法的方法对象中

* :从技术上讲,每次MyClassB testStrings " ==> false" DoIt,即你只需按键击执行代码,就会被编译为Squeak中的一个方法。

答案 2 :(得分:0)

这是我从在线散布的免费Smalltalk书籍中得知的,但我找不到参考:

正如您所期望的那样,类的实例是内存中的唯一对象。 deepCopy 首先有意创建一个对象,然后在其中存储现有实例的副本。

然而,Smalltalk将数字,字符和字符串视为原始数据类型。当文字数据(也称为文字)被分配给变量时,它们首先针对用户不可见的本地范围字典进行检查,并保留文字以检查它们是否为已经添加到它。如果它们没有,它们将被添加到字典中,变量将指向字典字段。如果之前已分配了相同的文字数据,则新变量将仅指向包含相同文字的本地范围字典字段。这意味着分配了相同文字的两个或多个变量指向同一个字典字段,因此是相同的对象。这就是为什么你的问题中的第二个比较是真实的。