F#为=运算符使用结构相等,这几乎总是你想要的:
let a = [1; 2; 3]
let b = [1; 2; 3]
printfn "%A" (a = b) // Prints "true"
Run Code Online (Sandbox Code Playgroud)
但是在某些算法中,能够问"这两件事是同一个对象吗?"非常重要.例如,这可以帮助检测图中的循环.那么我如何在F#中要求引用相等?即,我如何编写isSameObject下面的功能?
let isSameObject x y = ???
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"
Run Code Online (Sandbox Code Playgroud)
rmu*_*unn 42
事实证明,答案是使用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"
Run Code Online (Sandbox Code Playgroud)
我可以在Stack Overflow上找到一个问题: F#中的短切平等检查?因为那个问题的主题几乎让我一眼就看过它,我想我会再问(并回答)这个问题.希望这个问题的主题将更容易找到谷歌搜索"F#中的参考平等"等术语.
怎么样obj.ReferenceEquals?
在评论中,Fyodor Soikin询问有什么问题obj.ReferenceEquals.答案是"不多",但有两种方法LanguagePrimitives.PhysicalEquality比obj.ReferenceEquals大多数F#代码更好:
1)PhysicalEquality抛出一个编译器错误,当你传递两个不同类型的,而obj.ReferenceEquals仅仅需要两个objS和因此愉快地尝试将比较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
Run Code Online (Sandbox Code Playgroud)
2)PhysicalEquality不会让你比较值类型,只有引用类型.obj.ReferenceEquals将允许您比较两个值类型,并将隐式地将它们打包.但是它将每个单独分开,这意味着即使你给它"相同"的值对象它也总是返回false:
let n = 3
let n' = n
obj.ReferenceEquals(n,n') // Returns false!
LanguagePrimitives.PhysicalEquality n n' // Compiler error
Run Code Online (Sandbox Code Playgroud)
当然,还有另一个不同之处,可归结为个人偏好和易用性.PhysicalEquality采用curried风格的参数,可以很好地与类型推断和部分应用程序配合使用.obj.ReferenceEquals采用tupled风格的参数,这意味着它使用起来有点难看.
出于所有这些原因,LanguagePrimitives.PhysicalEquality在几乎每种情况下使用都比使用更好obj.ReferenceEquals.