『软件工程』计算机界 TOP 3 难题:“相等”是软件工程中许多重大问题的根源( 二 )


对于引用类型(如对象)也应当进行结构比较 。 考虑一个单元测试 , 你希望检查返回的对象是否等于你期待的值 。 在使用结构相等的语言中 , 这个操作非常简单:
[]let ``The result of the calculation is the expected value`` = let expected = { SomeField = "Some value"; SomeOtherField = 15; StillAnotherField = true; ... } let actual = calculate Assert.AreEqual(expected, actual) 但如果语言不支持结构相等 , 而开发者需要自行开发 , 就会遇到难题 。
引用相等
但正如我刚才说过的那样 , 某些特定情况下不应该使用结构相等 。 一种情况就是语言支持变量内容改变的情况 , 而绝大多数编程语言都支持 。 当某个变量的值被改变后 , 说这个变量等于另一个变量显然是不合理的 。 当然 , 你可以说在进行比较的时刻 , 这两个变量(在结构上)是相等的 , 比如在单元测试的最后一行时是相等的 , 但一般情况下你无法假设这两个变量是同一个东西 。 这点理解起来有些困难 , 我来举例说明 。
我们假设有一个对象 , 表示一个人 。 在采用了结构相等的F#中 , 我可以这样写:
type Person = { Name : string; Age : integer; Offspring : Person list } 现在我有两个朋友Jane和Sue , 她们都有一个叫John的儿子 , 年龄都是15岁 。 他们是不同的人 , 但姓名和年龄都一样 。 没问题!
let jane = { Name = "Jane"; Age = 47; Offspring = [ { Name = "John"; Age = 15; Offspring = [] } ] }let sue = { Name = "Sue"; Age = 35; Offspring = [ { Name = "John"; Age = 15; Offspring = [] } ] } 也可以这样写:
let john = { Name = "John"; Age = 15; Offspring =};let jane = { Name = "Jane"; Age = 47; Offspring = [ john ] }let sue = { Name = "Sue"; Age = 35; Offspring = [ john ] } 这两段代码的功能完全一样 。 我没办法区别两个儿子 , 即使我知道他们是不同的人 。 但这没有问题!如果我需要区别他们 , 我可以把他们DNA的hash之类的属性加到Person类型中 。 但如果我只需要知道他们的名字和年龄 , 那么是否能区分两个对象并不重要 , 因为不管怎么区分 , 它们的值都是一样的 。
假设Jane的儿子改名成Pat 。 F#不支持改变变量的值 , 所以我需要为John(还有Jane!)创建新的Person实例:
let newJane = { Name = "Jane"; Age = 47; Offspring = [ { Name = "Pat"; Age = 15; Offspring = [] } ] } 这个新的变量newJane似乎有点奇怪 , 但实际上并不会构成问题 。 上面的代码没有问题 。 现在用C#试一下 , 在C#中 , 变量默认情况下是可以修改的:
var john = new Person("John", 15, );var jane = new Person("Jane", 15, new List { john });var sue = new Person("Sue", 15, new List { john }); 这段代码显然是不正确的:如果Jane的儿子改名为Pat , 我可以直接改变引用的值:
jane.Offspring.First.Name = "Pat"; 但我就会发现Sue的儿子也改名了!因此 , 即使两个儿子最初的名字是一样的 , 但他们并不相等!所以我应该写成:
var jane = new Person("Jane", 15, new List { new Person("John", 15, ) });var sue = new Person("Sue", 15, new List { new Person("John", 15, ) }); 这样Jane和Sue的孩子就是引用不相等 。 所以 , 在可以改变变量内容的语言中 , 默认采用引用相等是合理的 。


推荐阅读