Szukaj…


Uwagi

Jednostki w czasie wykonywania

Jednostki miary są używane tylko do sprawdzania statycznego przez kompilator i nie są dostępne w czasie wykonywania. Nie można ich używać w refleksji ani w metodach takich jak ToString .

Na przykład, C # daje double bez jednostek dla pola typu float<m> zdefiniowanego i udostępnionego z biblioteki F #.

Zapewnienie spójnych jednostek w obliczeniach

Jednostki miary to dodatkowe adnotacje typu, które można dodawać do liczb zmiennoprzecinkowych lub liczb całkowitych. Można ich użyć do sprawdzenia w czasie kompilacji, czy obliczenia konsekwentnie używają jednostek.

Aby zdefiniować adnotacje:

[<Measure>] type m // meters
[<Measure>] type s // seconds
[<Measure>] type accel = m/s^2 // acceleration defined as meters per second squared

Po zdefiniowaniu można użyć adnotacji, aby sprawdzić, czy wyrażenie daje oczekiwany typ.

// Compile-time checking that this function will return meters, since (m/s^2) * (s^2) -> m
// Therefore we know units were used properly in the calculation.
let freeFallDistance (time:float<s>) : float<m> = 
    0.5 * 9.8<accel> * (time*time)    

// It is also made explicit at the call site, so we know that the parameter passed should be in seconds
let dist:float<m> = freeFallDistance 3.0<s>
printfn "%f" dist

Konwersje między jednostkami

[<Measure>] type m // meters
[<Measure>] type cm // centimeters

// Conversion factor
let cmInM = 100<cm/m>

let distanceInM = 1<m>
let distanceInCM = distanceInM * cmInM // 100<cm>

// Conversion function
let cmToM (x : int<cm>) = x / 100<cm/m>
let mToCm (x : int<m>) = x * 100<cm/m>

cmToM 100<cm> // 1<m>
mToCm 1<m> // 100<cm>

Zauważ, że kompilator F # nie wie, że 1<m> równa się 100<cm> . O ile to ważne, jednostki są osobnymi typami. Możesz napisać podobne funkcje do przeliczenia z metrów na kilogramy, a kompilator by się nie przejmował.

[<Measure>] type kg

// Valid code, invalid physics
let kgToM x = x / 100<kg/m>

Nie można zdefiniować jednostek miary jako wielokrotności innych jednostek, takich jak

// Invalid code
[<Measure>] type m = 100<cm>

Jednak zdefiniowanie jednostek „na coś”, na przykład Hertz, pomiar częstotliwości jest po prostu „na sekundę”, jest dość prosty.

// Valid code
[<Measure>] type s
[<Measure>] type Hz = /s

1 / 1<s> = 1 <Hz> // Evaluates to true

[<Measure>] type N = kg m/s // Newtons, measuring force. Note lack of multiplication sign.

// Usage
let mass = 1<kg>
let distance = 1<m>
let time = 1<s>

let force = mass * distance / time // Evaluates to 1<kg m/s>
force = 1<N> // Evaluates to true

Używanie LanguagePrimitives do zachowania lub ustawienia jednostek

Gdy funkcja nie zachowuje jednostek automatycznie z powodu operacji niższego poziomu, można użyć modułu LanguagePrimitives do ustawienia jednostek na operacjach podstawowych, które je obsługują:

/// This cast preserves units, while changing the underlying type
let inline castDoubleToSingle (x : float<'u>) : float32<'u> =
    LanguagePrimitives.Float32WithMeasure (float32 x)

Aby przypisać jednostki miary do zmiennoprzecinkowej podwójnej precyzji, wystarczy pomnożyć przez jedną z poprawnymi jednostkami:

[<Measure>]
type USD

let toMoneyImprecise (amount : float) =
   amount * 1.<USD>

Aby przypisać jednostki miary do wartości bez jednostki, która nie jest System.Double, na przykład, przybywając z biblioteki napisanej w innym języku, użyj konwersji:

open LanguagePrimitives

let toMoney amount =
   amount |> DecimalWithMeasure<'u>

Oto typy funkcji zgłoszone przez F # Interactive:

val toMoney : amount:decimal -> decimal<'u>
val toMoneyImprecise : amount:float -> float<USD>

Parametry typu jednostki miary

Atrybutu [<Measure>] można użyć w parametrach typu, aby zadeklarować typy ogólne w odniesieniu do jednostek miary:

type CylinderSize<[<Measure>] 'u> =
    { Radius : float<'u>
      Height : float<'u> }

Wykorzystanie testowe:

open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols

/// This has type CylinderSize<m>.
let testCylinder =
    { Radius = 14.<m>
      Height =  1.<m> }

Użyj standardowych typów jednostek, aby zachować zgodność

Na przykład typy jednostek SI zostały znormalizowane w bibliotece F # core, w Microsoft.FSharp.Data.UnitSystems.SI . Otwórz odpowiednią UnitNames , UnitNames lub UnitSymbols , aby z nich skorzystać. Lub, jeśli wymaganych jest tylko kilka jednostek SI, można je zaimportować za pomocą aliasów typu:

/// Seconds, the SI unit of time. Type abbreviation for the Microsoft standardized type.
type [<Measure>] s = Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s

Niektórzy użytkownicy zazwyczaj wykonują następujące czynności, których nie należy wykonywać, gdy definicja jest już dostępna:

/// Seconds, the SI unit of time
type [<Measure>] s // DO NOT DO THIS! THIS IS AN EXAMPLE TO EXPLAIN A PROBLEM.

Różnica staje się widoczna podczas łączenia z innym kodem, który odnosi się do standardowych typów SI. Kod odwołujący się do standardowych jednostek jest kompatybilny, podczas gdy kod definiujący własny typ jest niezgodny z żadnym kodem, który nie używa określonej definicji.

Dlatego zawsze używaj standardowych typów dla jednostek SI. Nie ma znaczenia, czy odwołujesz się do UnitNames czy UnitSymbols , ponieważ równoważne nazwy w tych dwóch odnoszą się do tego samego typu:

open Microsoft.FSharp.Data.UnitSystems.SI

/// This is valid, since both versions refer to the same authoritative type.
let validSubtraction = 1.<UnitSymbols.s> - 0.5<UnitNames.second>


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow