答案是使用
LanguagePrimitives.PhysicalEquality
函数:
let isSameObject = LanguagePrimitives.PhysicalEquality
let a = [1; 2; 3]
let b = [1; 2; 3]
let a' = a
printfn "%A" (isSameObject a b) // Prints "false"
printfn "%A" (isSameObject a a') // Prints "true"
我在Stack Overflow上只找到了一个与此相关的问题:如何在F#中使用短路等号检查?。由于那个问题的主题几乎让我忽略了它,所以我认为我会再问一遍这个问题(并回答)。希望这个问题的主题行会使它更容易被搜索到,比如“在F#中的引用相等性”等词汇。
obj.ReferenceEquals
怎么样?
Fyodor Soikin在评论中问obj.ReferenceEquals
有什么问题。答案是“没有太多问题”,但是对于大多数F#代码,LanguagePrimitives.PhysicalEquality
比obj.ReferenceEquals
更好的两个方面是:
1)当您传递给它两种不同的类型时,PhysicalEquality
会抛出编译器错误,而obj.ReferenceEquals
只接受两个obj
,因此会尝试将int list
与char list
进行比较。
let a = [1;2;3]
let b = ['a';'b';'c']
obj.ReferenceEquals(a,b) // Returns false
LanguagePrimitives.PhysicalEquality a b // Compiler error
2) PhysicalEquality
不允许比较值类型,只能比较引用类型。使用 obj.ReferenceEquals
可以比较两个值类型,并且会隐式地装箱它们。但是它会分别对每个值类型进行装箱,这意味着即使你给了它“相同”的值对象,它也会始终返回 false:
let n = 3
let n' = n
obj.ReferenceEquals(n,n') // Returns false!
LanguagePrimitives.PhysicalEquality n n' // Compiler error
当然,还有一个区别,归结为个人喜好和易用性。
PhysicalEquality
接受柯里化样式的参数,这与类型推断和部分应用程序很好地配合。
obj.ReferenceEquals
接受元组样式的参数,这意味着它稍微难看一些。
由于所有这些原因,在几乎每种情况下,使用
LanguagePrimitives.PhysicalEquality
要比使用
obj.ReferenceEquals
更好。
obj.ReferenceEquals
并不是 不好 的选择,但PhysicalEquality
更好,因为如果你尝试比较两种不同类型的对象,它将会返回类型错误(这几乎肯定是你代码中的一个bug,而你希望编译器能够帮助你捕捉到它)。 - rmunn