2016-08-30 27 views
22

F # wykorzystuje równości strukturalnej dla operatora =, który jest prawie zawsze to, co chcesz:Jak sprawdzić równość odniesienia w F #?

let a = [1; 2; 3] 
let b = [1; 2; 3] 
printfn "%A" (a = b) // Prints "true" 

Ale w niektórych algorytmów, to może być ważne, aby móc zapytać „Czy te dwie rzeczy tego samego obiektu ? " Może to pomóc na przykład w wykryciu cykli na wykresie. Jak mogę poprosić o równość referencyjną w F #? Np. Jak napisać poniżej funkcję 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" 

Odpowiedz

34

Odpowiedź, jak się okazuje, jest użycie 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" 

Było dokładnie jedno pytanie udało mi się znaleźć na przepełnienie stosu, który poprosił o tym: short-cutting equality checking in F#? I od tematu to pytanie niemal sprawił, że rzucam okiem tuż obok, pomyślałem, że znowu zadam (i odpowiem) na to pytanie. Mam nadzieję, że temat tego pytania będzie łatwiej znaleźć podczas Googling dla takich terminów jak "referencyjna równość w F #".

Co z numerem obj.ReferenceEquals?

W komentarzu Fyodor Soikin pyta, co jest nie tak z obj.ReferenceEquals. Odpowiedź brzmi „nie bardzo”, ale istnieją dwa sposoby, w których LanguagePrimitives.PhysicalEquality jest lepsza niż obj.ReferenceEquals dla większości F # Kod:

1) PhysicalEquality generuje błąd kompilatora kiedy przechodzą dwa różne typy, natomiast obj.ReferenceEquals zajmuje tylko dwa obj s, a więc szczęśliwie próbuje porównać int list do 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 nie pozwoli Ci porównać typy wartości, tylko typy referencyjne. obj.ReferenceEquals pozwoli ci porównać dwa typy wartości i domyślnie je najpierw zapełni. Ale to pudełka każda oddzielnie, co oznacza, że ​​będzie zawsze return false nawet jeśli dał mu „ten sam” obiekt o wartości:

let n = 3 
let n' = n 
obj.ReferenceEquals(n,n') // Returns false! 
LanguagePrimitives.PhysicalEquality n n' // Compiler error 

i, oczywiście, jest jeszcze jedna różnica, która sprowadza się do osobistych preferencje i łatwość użycia. PhysicalEquality ma parametry w stylu curry, które ładnie grają z wnioskiem o typ i aplikacją częściową. obj.ReferenceEquals przyjmuje parametry w stylu krotki, co oznacza, że ​​jest nieco brzydszy w użyciu.

Z tych wszystkich powodów, LanguagePrimitives.PhysicalEquality lepiej jest użyć w prawie każdy scenariusz, niż obj.ReferenceEquals.

+3

Coś nie tak z dobrym starym 'obj.ReferenceEquals'? –

+0

@FyodorSoikin - Napisałem dwa komentarze w odpowiedzi na twoje pytanie, a następnie zdałem sobie sprawę, że będą lepsze w odpowiedzi, z przykładami kodu. Więc proszę: 'obj.ReferenceEquals' nie jest ** zły **, ale' PhysicalEquality' jest lepszy, ponieważ daje błędy typu, jeśli spróbujesz porównać dwa różne typy. (Co jest prawie na pewno błędem w twoim kodzie, a ty * chcesz * kompilatorem, aby pomóc ci go złapać). – rmunn