여기 내 제한된 경험을 바탕으로 수집 한 내용은 다음과 같습니다
그러나, 결과 유형은 IEquatable<MyType>
와 호환되지 않습니다.
올바르지 않습니다. 결과 유형이 IEquatable<MyType>
입니다. ILDasm에서 확인할 수 있습니다.예 :
[<StructuralEquality;StructuralComparison>]
type SomeType = {
Value : int
}
let someTypeAsIEquatable = { Value = 3 } :> System.IEquatable<SomeType>
someTypeAsIEquatable.Equals({Value = 3}) |> ignore // calls Equals(SomeType) directly
아마도
방금 수행하는 경우 있도록, F 번호가 C#을 같은 암시 업 캐스팅을하지 않는 방법으로 혼동 :
{ Value = 3 }.Equals({Value = 4})
이 실제로 같음 (OBJ)를 호출 것 대신 C#에서 오는 기대에 반하는 인터페이스 멤버의.
궁금하네요하는 F #의 원인 권투의 경우 평등 테스트
한 일반적이고 애 태우게하는 경우, 예를 들어에 정의 된 구조체입니다 예를 들어, C# 및 IEquatable<T>
을 구현 :
public struct Vector2f : IEquatable<Vector2f>
또는 유사 예 IEquatable<T>
의 맞춤 구현 F 번호에 정의 된 구조체 :
[<Struct;CustomEquality;NoComparison>]
type MyVal =
val X : int
new(x) = { X = x }
override this.Equals(yobj) =
match yobj with
| :? MyVal as y -> y.X = this.X
| _ -> false
interface System.IEquatable<MyVal> with
member this.Equals(other) =
other.X = this.X
는 =
연산자이 구조체의 두 인스턴스 비교 실제로 Equals(MyVal)
대신 Equals(obj)
을 호출하므로 에서 복싱이 발생하고 두 값은과 비교됩니다 (그리고 캐스팅 및 언 박싱). 참고 : 나는 이것을 bug on the Visualfsharp Github으로보고했으며 분명히이 경우는 나중에 수정해야합니다.
그리고 확실하게 도움이 될 IEquatable<T>
으로 전송하면 좋겠지 만 그 자체로 복싱 작업입니다. 그러나 적어도 당신은이 방법으로 두 권투 중 하나를 구할 수 있습니다.
나는 혼란 스럽다. 무슨 일 이니? 유형이 컬렉션 키 또는 빈번한 동등성 테스트로 사용될 수있는 경우 적절한 균등 구현은 어떤 모양입니까?
나는 당신만큼 혼란 스럽습니다. F #은 매우 GC-happy (GC 튜플을 두려워하지 않고 구조체 레코드 나 DU를 지원하지 않음) 인 것처럼 보입니다. 심지어 기본 동작 :
[<Struct>]
type MyVal =
val X : int
new(x) = { X = x }
for i in 0 .. 1000000 do
(MyVal(i) = MyVal(i + 1)) |> ignore;;
Réel : 00:00:00.008, Processeur : 00:00:00.015, GC gén0: 4, gén1: 1, gén2: 0
여전히 권투 및 과도한 GC 압력의 원인! 해결 방법은 아래를 참조하십시오.
예를 들어 유형을 키로 사용해야하는 경우 어떻게 될까요? 사전? 음, 그것이 System.Collections.Generics.Dictionary
이라면, F # 동등 연산자를 사용하지 않아도됩니다. 그러나이 연산자를 사용하는 F #에 정의 된 컬렉션은 분명히 권투 문제에 부딪 힐 수 있습니다.
I가 최우선이 GetHashCode과 같음되는 경우가 있는지 (...) 궁금 IEquatable < 구현있어>를 StructuralEqualityAttribute 를 사용하는 것이 바람직하다.
요점은 사용자 정의 동등성을 정의하는 것이고,이 경우 StructuralEqualityAttribute
대신 CustomEqualityAttribute
을 사용합니다.
그렇다면 = 연산자의 성능을 저하시키지 않고 수행 할 수 있습니까?
업데이트 : 내가 기본 (=)를 피하고 직접 IEquatable (T) .Equals를 사용하는 것이 좋습니다. 이를 위해 인라인 연산자를 정의 할 수도 있고, 심지어는 (=) 재정의 할 수도 있습니다. 이것은 F #의 거의 모든 유형에 대한 권한을 가지며 나머지는 컴파일하지 않으므로 미묘한 버그에 빠지지 않습니다. I describe the approach in detail here.
원래
: F # 4.0을 시작으로 , 다음 (thanks latkin)을 수행 할 수 있습니다
[<Struct>]
type MyVal =
val X : int
new(x) = { X = x }
static member op_Equality(this : MyVal, other : MyVal) =
this.X = other.X
module NonStructural =
open NonStructuralComparison
let test() =
for i in 0 .. 10000000 do
(MyVal(i) = MyVal(i + 1)) |> ignore
// Real: 00:00:00.003, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
NonStructural.test()
NonStructuralComparison 모듈은 단순히 op_Equality
를 호출하는 버전으로 기본 =
우선합니다. NoEquality
및 NoComparison
속성을 구조체에 추가하여 잘못 수행 된 기본값 인 =
을 실수로 사용하지 않도록합니다.