Freigeben über


Maßeinheiten

Gleitkomma- und signierte ganzzahlige Werte in F# können zugeordnete Maßeinheiten aufweisen, die in der Regel verwendet werden, um Länge, Volume, Masse usw. anzugeben. Mithilfe von Mengen mit Einheiten können Sie den Compiler überprüfen, ob arithmetische Beziehungen über die richtigen Einheiten verfügen, wodurch Programmierfehler vermieden werden können.

Hinweis

Diese Beispiele zeigen die Korrektheit bei arithmetischen Berechnungen mit Maßeinheiten, das Feature kann auch zum Hinzufügen von typsicheren Anmerkungen mit null Darstellungskosten zu anderen Typen genutzt werden, mit Ansatz wie FSharp.UMX-Projekt .

Syntax

[<Measure>] type unit-name [ = measure ]

Bemerkungen

Die vorherige Syntax definiert den Einheitennamen als Maßeinheit. Der optionale Teil wird verwendet, um ein neues Measure in Bezug auf zuvor definierte Einheiten zu definieren. Die folgende Zeile definiert z. B. das Maß cm (Zentimeter).

[<Measure>] type cm

In der folgenden Zeile wird das Maß ml (Milliliter) als kubische Zentimeter (cm^3) definiert.

[<Measure>] type ml = cm^3

In der vorherigen Syntax ist measure eine Formel, die Einheiten umfasst. In Formeln, die Einheiten umfassen, werden integrale Mächte unterstützt (positiv und negativ), Leerzeichen zwischen Einheiten geben ein Produkt der beiden Einheiten an, * gibt auch ein Produkt von Einheiten an und / gibt einen Quotienten von Einheiten an. Bei einer gegenseitigen Einheit können Sie entweder eine negative ganzzahlige Potenz verwenden oder eine / , die eine Trennung zwischen dem Zähler und dem Nenner einer Einheitsformel angibt. Mehrere Einheiten im Nenner sollten von Klammern umgeben sein. Einheiten, die durch Leerzeichen getrennt sind, / werden als Teil des Nenners interpretiert, aber alle Einheiten, die einem Folgen folgen * , werden als Teil des Zählers interpretiert.

Sie können 1 in Einheitenausdrücken verwenden, entweder allein, um eine dimensionlose Menge anzugeben, oder zusammen mit anderen Einheiten, z. B. im Zähler. Beispielsweise würden die Einheiten für eine Rate als 1/s, wobei s Sekunden angegeben werden, geschrieben. Klammern werden in Einheitenformeln nicht verwendet. Sie geben keine numerischen Konvertierungskonstanten in den Einheitenformeln an; Sie können jedoch Konvertierungskonstanten mit Einheiten separat definieren und in einheitengeprüften Berechnungen verwenden.

Unit formulas that mean the same thing can be written in various equivalent ways. Daher wandelt der Compiler Einheitenformeln in eine konsistente Form um, die negative Mächte in Kehrwerte konvertiert, Einheiten in einen einzelnen Zähler und einen Nenner gruppiert und die Einheiten im Zähler und Nenner alphabetisiert.

Beispielsweise werden die Einheitenformeln kg m s^-2 und m /s s * kg beide in kg m/s^2.

Sie verwenden Maßeinheiten in Gleitkommaausdrücken. Die Verwendung von Gleitkommazahlen zusammen mit den zugehörigen Maßeinheiten fügt eine weitere Ebene der Typsicherheit hinzu und verhindert, dass fehler in Formeln auftreten können, wenn Sie schwach typierte Gleitkommazahlen verwenden. Wenn Sie einen Gleitkommaausdruck schreiben, der Einheiten verwendet, muss die Einheiten im Ausdruck übereinstimmen.

Sie können Literale mit einer Einheitsformel in winkeln Klammern kommentieren, wie in den folgenden Beispielen gezeigt.

1.0<cm>
55.0<miles/hour>

Sie setzen kein Leerzeichen zwischen der Zahl und der eckigen Klammer. Sie können jedoch ein Literalsuffix wie fim folgenden Beispiel einschließen.

// The f indicates single-precision floating point.
55.0f<miles/hour>

Eine solche Anmerkung ändert den Typ des Literals von seinem Grundtyp (z float. B. ) in einen bemaßten Typ, z float<cm> . B. oder in diesem Fall float<miles/hour>. Eine Einheitenanmerkung von <1> gibt eine dimensionslose Menge an, und ihr Typ entspricht dem Grundtyp ohne Einen Einheitenparameter.

Der Typ einer Maßeinheit ist ein Gleitkomma- oder signierter Integraltyp zusammen mit einer zusätzlichen Einheitsanmerkung, die in Klammern angegeben ist. Wenn Sie also den Typ einer Konvertierung von g (Gramm) in kg (Kilogramm) schreiben, beschreiben Sie die Typen wie folgt.

let convertg2kg (x : float<g>) = x / 1000.0<g/kg>

Maßeinheiten werden für die Überprüfung der Kompilierungszeiteinheit verwendet, werden jedoch nicht in der Laufzeitumgebung beibehalten. Daher wirken sie sich nicht auf die Leistung aus.

Maßeinheiten können auf jeden Beliebigen Typ angewendet werden, nicht nur auf Gleitkommatypen; Allerdings unterstützen nur Gleitkommatypen, signierte integrale Typen und Dezimaltypen dimensionierte Mengen. Daher ist es nur sinnvoll, Maßeinheiten für die Grundtypen und Aggregate zu verwenden, die diese Grundtypen enthalten.

Das folgende Beispiel veranschaulicht die Verwendung von Maßeinheiten.

// Mass, grams.
[<Measure>] type g
// Mass, kilograms.
[<Measure>] type kg
// Weight, pounds.
[<Measure>] type lb

// Distance, meters.
[<Measure>] type m
// Distance, cm
[<Measure>] type cm

// Distance, inches.
[<Measure>] type inch
// Distance, feet
[<Measure>] type ft

// Time, seconds.
[<Measure>] type s

// Force, Newtons.
[<Measure>] type N = kg m / s^2

// Pressure, bar.
[<Measure>] type bar
// Pressure, Pascals
[<Measure>] type Pa = N / m^2

// Volume, milliliters.
[<Measure>] type ml
// Volume, liters.
[<Measure>] type L

// Define conversion constants.
let gramsPerKilogram : float<g kg^-1> = 1000.0<g/kg>
let cmPerMeter : float<cm/m> = 100.0<cm/m>
let cmPerInch : float<cm/inch> = 2.54<cm/inch>

let mlPerCubicCentimeter : float<ml/cm^3> = 1.0<ml/cm^3>
let mlPerLiter : float<ml/L> = 1000.0<ml/L>

// Define conversion functions.
let convertGramsToKilograms (x : float<g>) = x / gramsPerKilogram
let convertCentimetersToInches (x : float<cm>) = x / cmPerInch

Im folgenden Codebeispiel wird veranschaulicht, wie Sie aus einer dimensionlosen Gleitkommazahl in einen bemaßten Gleitkommawert konvertieren. Sie multiplizieren einfach mit 1,0, wobei die Dimensionen auf 1,0 angewendet werden. Sie können dies in eine Funktion wie degreesFahrenheit.

Wenn Sie bemaßte Werte auch an Funktionen übergeben, die bemaßte Gleitkommazahlen erwarten, müssen Sie die Einheiten abbrechen oder mithilfe des float Operators in float diese umwandeln. In diesem Beispiel dividieren 1.0<degC> Sie nach den Argumenten printf , da printf sie dimensionslose Mengen erwartet.

[<Measure>] type degC // temperature, Celsius/Centigrade
[<Measure>] type degF // temperature, Fahrenheit

let convertCtoF ( temp : float<degC> ) = 9.0<degF> / 5.0<degC> * temp + 32.0<degF>
let convertFtoC ( temp: float<degF> ) = 5.0<degC> / 9.0<degF> * ( temp - 32.0<degF>)

// Define conversion functions from dimensionless floating point values.
let degreesFahrenheit temp = temp * 1.0<degF>
let degreesCelsius temp = temp * 1.0<degC>

printfn "Enter a temperature in degrees Fahrenheit."
let input = System.Console.ReadLine()
let parsedOk, floatValue = System.Double.TryParse(input)
if parsedOk
   then
      printfn "That temperature in Celsius is %8.2f degrees C." ((convertFtoC (degreesFahrenheit floatValue))/(1.0<degC>))
   else
      printfn "Error parsing input."

Die folgende Beispielsitzung zeigt die Ausgaben und Eingaben in diesen Code.

Enter a temperature in degrees Fahrenheit.
90
That temperature in degrees Celsius is    32.22.

Grundtypen, die Maßeinheiten unterstützen

Die folgenden Typen oder Abkürzungsaliasen unterstützen Maßeinheitsanmerkungen:

F#-Alias CLR-Typ
float32/single System.Single
float/double System.Double
decimal System.Decimal
sbyte/int8 System.SByte
int16 System.Int16
int/int32 System.Int32
int64 System.Int64
byte/uint8 System.Byte
uint16 System.UInt16
uint/uint32 System.UInt32
uint64 System.UIn64
nativeint System.IntPtr
unativeint System.UIntPtr

Sie können z. B. eine nicht signierte ganze Zahl wie folgt kommentieren:

[<Measure>]
type days

let better_age = 3u<days>

Das Hinzufügen von nicht signierten ganzzahligen Typen zu diesem Feature ist in F# RFC FS-1091 dokumentiert.

Vordefinierte Maßeinheiten

Eine Komponentenbibliothek ist im FSharp.Data.UnitSystems.SI Namespace verfügbar. Sie enthält SI-Einheiten in ihrer Symbolform (z m . B. für Meter) im UnitSymbols Unternamenszeichen und im vollständigen Namen (z meter . B. für Meter) im UnitNames Unternamenspace.

Verwenden generischer Einheiten

Sie können generische Funktionen schreiben, die mit Daten arbeiten, die über eine zugeordnete Maßeinheit verfügen. Dazu geben Sie einen Typ zusammen mit einer generischen Einheit als Typparameter an, wie im folgenden Codebeispiel gezeigt.

// Distance, meters.
[<Measure>] type m
// Time, seconds.
[<Measure>] type s

let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y

let v1 = 3.1<m/s>
let v2 = 2.7<m/s>
let x1 = 1.2<m>
let t1 = 1.0<s>

// OK: a function that has unit consistency checking.
let result1 = genericSumUnits v1 v2
// Error reported: mismatched units.
// Uncomment to see error.
// let result2 = genericSumUnits v1 x1

Erstellen von Sammlungstypen mit generischen Einheiten

Der folgende Code zeigt, wie Sie einen Aggregattyp erstellen, der aus einzelnen Gleitkommawerten besteht, die über generische Einheiten verfügen. Dadurch kann ein einzelner Typ erstellt werden, der mit einer Vielzahl von Einheiten funktioniert. Darüber hinaus erhalten generische Einheiten die Typsicherheit, indem sichergestellt wird, dass ein generischer Typ mit einer Gruppe von Einheiten ein anderer Typ ist als derselbe generische Typ mit einer anderen Gruppe von Einheiten. Die Basis dieser Technik ist, dass das Measure Attribut auf den Typparameter angewendet werden kann.

 // Distance, meters.
[<Measure>] type m
// Time, seconds.
[<Measure>] type s

// Define a vector together with a measure type parameter.
// Note the attribute applied to the type parameter.
type vector3D<[<Measure>] 'u> = { x : float<'u>; y : float<'u>; z : float<'u>}

// Create instances that have two different measures.
// Create a position vector.
let xvec : vector3D<m> = { x = 0.0<m>; y = 0.0<m>; z = 0.0<m> }
// Create a velocity vector.
let v1vec : vector3D<m/s> = { x = 1.0<m/s>; y = -1.0<m/s>; z = 0.0<m/s> }

Einheiten zur Laufzeit

Maßeinheiten werden für die Überprüfung statischer Typen verwendet. Wenn Gleitkommawerte kompiliert werden, werden die Maßeinheiten entfernt, sodass die Einheiten zur Laufzeit verloren gehen. Daher ist jeder Versuch, Funktionen zu implementieren, die von der Überprüfung der Einheiten zur Laufzeit abhängen, nicht möglich. Die Implementierung einer ToString Funktion zum Drucken der Einheiten ist beispielsweise nicht möglich.

Konvertierungen

Wenn Sie einen Typ mit Einheiten (z. B. ) in einen Typ konvertieren möchten, float<'u>der keine Einheiten enthält, können Sie die Standardkonvertierungsfunktion verwenden. Sie können z. B. zum Konvertieren in einen float Wert verwendenfloat, der keine Einheiten enthält, wie im folgenden Code gezeigt.

[<Measure>]
type cm
let length = 12.0<cm>
let x = float length

Wenn Sie einen einheitenlosen Wert in einen Wert mit Einheiten konvertieren möchten, können Sie mit einem Wert von 1 oder 1,0 multiplizieren, der mit den entsprechenden Einheiten versehen ist. Zum Schreiben von Interoperabilitätsebenen gibt es jedoch auch einige explizite Funktionen, mit denen Sie einheitenlose Werte in Werte mit Einheiten konvertieren können. Diese befinden sich im FSharp.Core.LanguagePrimitives-Modul . Wenn Sie z. B. von einer Einheit in float eine float<cm>Einheit konvertieren möchten, verwenden Sie "FloatWithMeasure", wie im folgenden Code gezeigt.

open Microsoft.FSharp.Core
let height:float<cm> = LanguagePrimitives.FloatWithMeasure x

Siehe auch