2015-01-10 6 views
2

데이터 구조의 키 역할을하기 위해 Guids와 문자열을 사용합니다. C#에서는 ID가 OrderId 일 때 찾고있는 ID가없는 이벤트가 발생하지 않고 왜 ContractId와 일치하는지 궁금해하는 많은 시간을 보냈습니다. 내가하고 싶은 것은이 전체 오류 클래스를 방지하는 것입니다.F #에서 형식의 비 호환 버전 만들기

let contract = 
    { Schedule = Guid.Empty; TickTable = Guid.Empty; Price = 0.; Quantity = 0. } 
contract.Schedule = contract.TickTable;; // true - ugh 
contract.Price = contract.Quantity;; // true - ugh 

내가 한 가지 문제 다음과 같이 해결할 수 :

[<Measure>] type dollars 
[<Measure>] type volume 
type Contract = 
    { Schedule : Guid; TickTable : Guid; 
     Price : float<dollars>; Quantity : float<volume> } 
나는이 문제가 지금

type Contract = { Schedule : Guid; TickTable : Guid; Price : float; Quantity : float } 

:

나는 다음과 같은 기본 데이터 유형과 계약을 체결 한 상상

이제 우리는 :

let contract = 
    { Schedule = Guid.Empty; TickTable = Guid.Empty; 
     Price = 0.<dollars>; Quantity = 0.<volume> } 
contract.Schedule = contract.TickTable;; // true - ugh 
contract.Price = contract.Quantity;; // type mismatch - yay 

유형 불일치가 생길 정도로 Guids를 꾸밀 수있는 방법이 있습니까? 컴파일 시간에 영향을주고 싶습니다. 컴파일 된 코드는 측정 단위와 동일합니다.

은 내가 다음을 수행 할 수 있습니다 알고 있지만, 그것은 추한 것, 내가 그것을 실행 시간에 미치는 영향의 원인 기대 : 유형을 작성하여, 당신은 심지어 일반적으로, 단위가 어떤 형식을 래핑 할 수

[<Measure>] type dollars 
[<Measure>] type volume 
type ScheduleId = ScheduleKey of Guid 
type TickTableId = TickTableKey of Guid 
type Contract = 
    { Schedule : ScheduleId; TickTable : TickTableId; 
     Price : float<dollars>; Quantity : float<volume> } 

let contract = 
    { Schedule = ScheduleKey Guid.Empty; TickTable = TickTableKey Guid.Empty; 
     Price = 0.<dollars>; Quantity = 0.<volume> } 
contract.Schedule = contract.TickTable;; // type error - yay 
contract.Price = contract.Quantity;; // type mismatch - yay 
+1

당신이 갖고있는 해결책은 적당합니다. 나는 런타임에 미치는 영향이 너무 나쁠 것이라고 생각하지 않습니다. –

+0

@JohnPalmer : 'Guid'를 값 유형에서 참조 유형으로 효과적으로 바꾸고 있으며 많은 레코드로 눈에 띄는 GC 변동을 유발할 수 있습니다. DU를 struct로 컴파일하는 것이 가능하다면 ... : - [ – ildjarn

+4

DU 대신에 id를 전용 struct 유형으로 바꿀 수 있습니다. – latkin

답변

3

[<Measure>] 형식 인수. 또한 주석에서 암시하는 것처럼 struct (which is allocated in place, not as a new object)을 사용하면 추가 할당 및 간접 참조를 줄일 수 있습니다.

일반 단위의 측정 값을 인식 래퍼 :

type [<Struct>] UnitAware<'T, [<Measure>] 'u> = 
    val Raw : 'T 
    new (raw) = { Raw = raw } 

let withUnit<[<Measure>] 'u> a = UnitAware<_, 'u>(a) 

이 방법은 임의의 유형은 단순히 withUnit<myUnit> 통해 감싸고 .Raw로 언 래핑하는 단위의 측정 값을 인식 치형 래퍼를들 수있다 :

let a = 146L |> withUnit<dollars> 
let b = 146L |> withUnit<volume> 

a = b // Type mismatch. 

구조적 비교로 인해 동일한 단위 및 동일한 내용의 두 구조체 래퍼도 동일합니다. 다른 측정 단위 사용법과 마찬가지로 실행시 추가 유형 안전이 손실됩니다. box a = box b이 참일 경우 box 1.<dollars> = box 1.<volumes>과 같습니다.