Suche…
Bemerkungen
Einheiten zur Laufzeit
Maßeinheiten werden nur für die statische Überprüfung durch den Compiler verwendet und sind zur Laufzeit nicht verfügbar. Sie können nicht in Reflektionen oder in Methoden wie ToString
.
Beispielsweise gibt C # ein double
ohne Einheiten für ein Feld des Typs float<m>
das durch eine F # -Bibliothek definiert und aus dieser freigegeben wird.
Sicherstellung konsistenter Einheiten in Berechnungen
Maßeinheiten sind zusätzliche Typanmerkungen, die zu Gleitkommazahlen oder Ganzzahlen hinzugefügt werden können. Sie können verwendet werden, um während der Kompilierzeit zu überprüfen, ob die Berechnungen Einheiten einheitlich verwenden.
Anmerkungen definieren:
[<Measure>] type m // meters
[<Measure>] type s // seconds
[<Measure>] type accel = m/s^2 // acceleration defined as meters per second squared
Einmal definiert, können Anmerkungen verwendet werden, um zu überprüfen, ob ein Ausdruck den erwarteten Typ ergibt.
// 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
Umrechnungen zwischen Einheiten
[<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>
Beachten Sie, dass der F # -Compiler nicht weiß, dass 1<m>
100<cm>
. Die Einheiten sind, soweit es wichtig ist, separate Typen. Sie können ähnliche Funktionen schreiben, um von Metern in Kilogramm zu konvertieren, und der Compiler würde das nicht interessieren.
[<Measure>] type kg
// Valid code, invalid physics
let kgToM x = x / 100<kg/m>
Es ist nicht möglich, Maßeinheiten als Vielfache anderer Einheiten wie z. B. zu definieren
// Invalid code
[<Measure>] type m = 100<cm>
Einheiten "pro etwas" zu definieren, zum Beispiel Hertz, das Messen der Frequenz ist einfach "pro Sekunde", ist ziemlich einfach.
// 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
Verwendung von LanguagePrimitives zum Erhalten oder Einstellen von Einheiten
Wenn eine Funktion Einheiten aufgrund untergeordneter Operationen nicht automatisch speichert, können Sie das Modul LanguagePrimitives
verwenden, um Einheiten für die Grundelemente festzulegen, die sie unterstützen:
/// This cast preserves units, while changing the underlying type
let inline castDoubleToSingle (x : float<'u>) : float32<'u> =
LanguagePrimitives.Float32WithMeasure (float32 x)
Um Maßeinheiten einem Gleitkommawert mit doppelter Genauigkeit zuzuordnen, multiplizieren Sie einfach mit den korrekten Einheiten mit eins:
[<Measure>]
type USD
let toMoneyImprecise (amount : float) =
amount * 1.<USD>
Um Maßeinheiten einem Wert ohne Einheiten zuzuweisen, der nicht System.Double ist, z. B. aus einer Bibliothek, die in einer anderen Sprache geschrieben wurde, verwenden Sie eine Konvertierung:
open LanguagePrimitives
let toMoney amount =
amount |> DecimalWithMeasure<'u>
Hier sind die von F # interactive gemeldeten Funktionstypen:
val toMoney : amount:decimal -> decimal<'u>
val toMoneyImprecise : amount:float -> float<USD>
Parameter der Maßeinheitenart
Das Attribut [<Measure>]
kann für Typparameter verwendet werden, um generische Typen in Bezug auf Maßeinheiten zu deklarieren:
type CylinderSize<[<Measure>] 'u> =
{ Radius : float<'u>
Height : float<'u> }
Testnutzung:
open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols
/// This has type CylinderSize<m>.
let testCylinder =
{ Radius = 14.<m>
Height = 1.<m> }
Verwenden Sie standardisierte Gerätetypen, um die Kompatibilität zu gewährleisten
In der F # -Kernbibliothek in Microsoft.FSharp.Data.UnitSystems.SI
beispielsweise Typen für SI-Einheiten standardisiert. Öffnen Sie den entsprechenden Sub-Namespace, UnitNames
oder UnitSymbols
, um diese zu verwenden. Wenn nur wenige SI-Einheiten erforderlich sind, können sie mit Typ-Aliasnamen importiert werden:
/// Seconds, the SI unit of time. Type abbreviation for the Microsoft standardized type.
type [<Measure>] s = Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s
Einige Benutzer neigen dazu, Folgendes zu tun, was nicht gemacht werden sollte, wenn bereits eine Definition verfügbar ist:
/// Seconds, the SI unit of time
type [<Measure>] s // DO NOT DO THIS! THIS IS AN EXAMPLE TO EXPLAIN A PROBLEM.
Der Unterschied wird beim Anschluss an anderen Code deutlich, der sich auf die Standard-SI-Typen bezieht. Code, der sich auf die Standardeinheiten bezieht, ist kompatibel, während Code, der seinen eigenen Typ definiert, nicht mit Code kompatibel ist, der seine spezifische Definition nicht verwendet.
Verwenden Sie daher immer die Standardtypen für SI-Einheiten. Es spielt keine Rolle, ob Sie sich auf UnitNames
oder UnitSymbols
beziehen, da sich gleichwertige Namen in diesen beiden auf denselben Typ beziehen:
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>