2014-02-15 1 views
1

다음 질문을 보면서이 문제가 발생했습니다. F# Unit of Measure, Casting without losing the measure type 이 unbox 코드를 사용하려고하지 않고 있습니다. 질문에 대답하면서 행동.F # 'unbox float x'대 'unbox int x'이상한 컴파일 결과

이유는 무엇입니까 다음 코드 작업이는 System.InvalidCastException 산출하면서

let intToFloat (x:int<'u>) : float<'u> = unbox float x 
intToFloat 1<second> 

: '입력'86-6 @ float32ToFloat '형식의 개체를 캐스팅 할 수 없습니다를 Microsoft.FSharp.Core.FSharpFunc` 2 [System.Single, System.Double] '.?

let float32ToFloat (x:float32<'u>) : float<'u> = unbox float x 
float32ToFloat 1.0f<second> 

나는 코드가 예상대로 작동 (float x) 주위에 괄호를 넣어 경우, 그래서 그것을 어떤 식 평가/타입 추론 규칙 있어야합니다 가정합니다. 정확히 여기서 무슨 일이 일어나고 있고 두 번째 경우에 흉막 괄호가 필요한 이유는 무엇입니까?

+0

Tomas의 답은 오류에 대해 설명 합니다만, 참고로 'unbox'가 최선의 방법은 아닙니다. 'LanguagePrimitives.FloatWithMeasure <'u>'을 사용해야하며, .NET 바이트 코드에서는 no-op로 변환됩니다. 반면에'unbox'는이 경우에는 필요없는 런타임 유형 검사를 추가합니다. – Tarmil

+0

@ Tarmil, 나는 그것을 알고 있었다. 'FloatWithMeasure'가 더 나은 옵션이라는 것을 확인해 주셔서 고마워요. (링크 된 질문에 대한 저의 대답을보십시오). 거기에 추가/확인해 주시겠습니까? –

+0

오, 내가 링크 된 질문에 귀하의 게시물을 보지 못했습니다. 그래서 우리는 꽤 똑같은 말을했습니다 :) – Tarmil

답변

3

코드 스 니펫의 미묘한 점은 unbox float x입니다. 컴파일러는 이것을 (unbox float) x으로 처리합니다. 결과적으로 두 가지 기능은 실제로 다음과 같이 처리됩니다

let intToFloat (x:int<'u>) : float<'u> = 
    let f = unbox float in f x 

let float32ToFloat (x:float32<'u>) : float<'u> = 
    let f = unbox float in f x 

그래서, 다른 유형의 기능 (안전하지) 캐스팅의 float 기능을 복용하고 다음을 요구하고있다. 형식은 첫 번째 경우에는 int<'u> -> float<'u>이고 두 번째 경우에는 float32<'u> -> float<'u>입니다.

나는 측정 단위가 실행시에 삭제되기 때문에, 이것은 int<'u> -> float<'u>로 변환 (하지만로 할 수 있습니다 그것은 int -> float 기본값하고, 컴파일러가 (모든 종류의 주석 제외) float 기능을 볼 때 때문에 첫 번째 작품 생각 두 번째 유형 - 안전하지 않은 캐스트를 수행 중이므로).

그래서, 주요 문제는 구현에 잘못된 괄호가있어서 (이는 매우 미묘한 문제로 이어진다). 아마도 당신은 다음과 같은 것을 원했을 것입니다 :

let intToFloat (x:int<'u>) : float<'u> = unbox (float x) 
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x) 
+0

그것은 interresting IL을 생성합니다. http://stackoverflow.com/a/21802111/17919 – gradbot

관련 문제