Maßeinheiten (F#)

In F# können Gleitkommawerten und Ganzzahlwerten mit Vorzeichen Maßeinheiten zugeordnet werden. Mit diesen werden i. d. R. Länge, Volumen, Masse usw. angegeben. Wenn Sie Mengen mit Einheiten verwenden, kann der Compiler überprüfen, ob arithmetische Beziehungen die ordnungsgemäßen Einheiten aufweisen. So lassen sich Programmierfehler leichter vermeiden.

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

Hinweise

In der vorherigen Syntax wird unit-name als Maßeinheit definiert. Im optionalen Teil wird ein neues Maß mit zuvor definierten Einheiten festgelegt. Beispielsweise wird in der folgenden Zeile das Maß cm (Zentimeter) definiert.

[<Measure>] type cm

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

[<Measure>] type ml = cm^3

In der vorherigen Syntax ist measure eine Formel mit Einheiten. In Formeln mit Einheiten werden ganzzahlige Potenzen (positiv und negativ) unterstützt, Leerzeichen zwischen Einheiten geben ein Produkt der beiden Einheiten an, * gibt ebenfalls ein Produkt von Einheiten an, und / gibt einen Quotienten von Einheiten an. Für eine als Kehrwert dargestellte Einheit können Sie entweder eine negative ganzzahlige Potenz oder / verwenden, um Zähler und Nenner einer Einheitenformel zu trennen. Mehrere Einheiten im Nenner müssen in Klammern eingeschlossen werden. Durch Leerzeichen getrennte Einheiten nach / werden als Teil des Nenners interpretiert, Einheiten nach * werden jedoch als Teil des Zählers interpretiert.

Sie können in Ausdrücken mit Einheiten die Zahl 1 verwenden, entweder allein, um eine dimensionslose Größe anzugeben, oder zusammen mit anderen Einheiten, z. B. im Zähler. Beispielsweise wird die Einheit für die Geschwindigkeit als 1/s geschrieben, wobei s Sekunden angibt. In Einheitenformeln werden keine Klammern verwendet. In den Einheitenformeln werden keine numerischen Konvertierungskonstanten angegeben. Sie können jedoch Konvertierungskonstanten mit Einheiten getrennt definieren und sie in Berechnungen mit Einheitenüberprüfung verwenden.

Einheitenformeln mit der gleichen Bedeutung können auf verschiedene Weise geschrieben werden. Daher konvertiert der Compiler Einheitenformeln in ein konsistentes Format, in dem negative Potenzen in Kehrwerte konvertiert, Einheiten in einem einzelnen Zähler und einem einzelnen Nenner angeordnet sowie die Einheiten im Zähler und Nenner alphabetisch sortiert werden.

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

Sie verwenden Maßeinheiten in Gleitkommaausdrücken. Durch die Verwendung von Gleitkommazahlen mit zugeordneten Maßeinheiten wird die Typsicherheit erhöht, und Fehler aufgrund von Einheitenkonflikten, die in Formeln auftreten können, wenn Sie schwach typisierte Gleitkommazahlen verwenden, lassen sich leichter vermeiden. Wenn Sie einen Gleitkommaausdruck mit Einheiten schreiben, müssen die Einheiten im Ausdruck übereinstimmen.

Sie können Literalen eine Anmerkung mit einer Einheitenformel in spitzen Klammern hinzufügen, wie in den folgenden Beispielen gezeigt.

1.0<cm>
55.0<miles/hour>

Zwischen der Zahl und der spitzen Klammer wird kein Leerzeichen eingefügt, jedoch können Sie ein Literalsuffix, z. B. f, einfügen, wie im folgenden Beispiel:

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

Durch eine solche Anmerkung wird der Typ des Literals von einem primitiven Typ (z. B. float) in einen dimensionierten Typ, z. B. float<cm> oder wie in diesem Fall float<miles/hour>, geändert. Die Einheitenanmerkung <1> gibt eine dimensionslose Größe an, deren Typ dem primitiven Typ ohne Einheitenparameter entspricht.

Der Typ einer Maßeinheit ist ein Gleitkommatyp oder ein ganzzahliger Typ mit Vorzeichen zusammen mit einer zusätzlichen Einheitenanmerkung in Klammern. Wenn Sie den Typ einer Konvertierung von g (Gramm) in kg (Kilogramm) schreiben, geben Sie die Typen wie folgt an.

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

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

Maßeinheiten können auf jeden Typ, nicht nur auf Gleitkommatypen, angewendet werden. Dimensionierte Größen werden jedoch nur von Gleitkommatypen, Ganzzahltypen mit Vorzeichen und Dezimaltypen unterstützt. Daher macht es nur Sinn, Maßeinheiten für primitive Typen und Aggregate zu verwenden, die primitive Typen 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 

// 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 eine dimensionslose Gleitkommazahl ohne Einheiten in einen dimensionierten Gleitkommawert konvertiert wird. Sie multiplizieren einfach mit 1,0, wobei die Dimensionen auf 1,0 angewendet werden. Sie können dies in einer Funktion, z. B. degreesFahrenheit, abstrahieren.

Wenn Sie dimensionierte Werte an Funktionen übergeben, die dimensionslose Gleitkommazahlen ohne Einheiten erwarten, müssen Sie die Einheiten weglassen oder mit dem float-Operator in float konvertieren. In diesem Beispiel dividieren Sie die Argumente für printf durch 1.0<degC>, da printf dimensionslose Größen 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 mutable floatValue = 0.
if System.Double.TryParse(input, &floatValue)
   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 Aus- und Eingaben dieses Codes an.

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

Verwenden von generischen Einheiten

Sie können generische Funktionen für Daten schreiben, denen eine Maßeinheit zugeordnet ist. Hierfür geben Sie einen Typ zusammen mit einer generischen Einheit als Typparameter an, wie im folgenden Beispiel veranschaulicht.

// 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 Aggregattypen mit generischen Einheiten

Im folgenden Code wird gezeigt, wie ein aggregierter Typ erstellt wird, der aus einzelnen Gleitkommawerten mit generischen Einheiten besteht. Dies ermöglicht das Erstellen eines einzelnen Typs, der für vielfältige Einheiten verwendet werden kann. Generische Einheiten bewahren außerdem die Typsicherheit, da sie verhindern, dass ein generischer Typ, der einen Satz von Einheiten aufweist, mit dem gleichen generischen Typ, der einen anderen Satz von Einheiten aufweist, identisch ist. Diesem Verfahren liegt zugrunde, 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. Beim Kompilieren von Gleitkommawerten werden die Maßeinheiten entfernt, daher sind die Einheiten zur Laufzeit nicht vorhanden. Aus diesem Grund kann keine Funktionalität implementiert werden, die von der Überprüfung der Einheiten zur Laufzeit abhängt. Beispielsweise ist es nicht möglich, die ToString-Funktion zum Ausgeben der Einheiten zu implementieren.

Konvertierungen

Um einen Typ mit Einheiten (z. B. float<'u>) in einen Typ ohne Einheiten zu konvertieren, können Sie die Standardkonvertierungsfunktion verwenden. Beispielsweise können Sie float zum Konvertieren in einen float-Wert ohne Einheiten verwenden, wie im folgenden Code dargestellt.

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

Um einen Wert ohne Einheiten in einen Wert mit Einheiten zu konvertieren, können Sie eine Multiplikation mit dem Wert 1 oder 1,0 durchführen, mit den entsprechenden Einheiten als Anmerkung. Zum Schreiben von Interoperabilitätsschichten stehen jedoch auch explizite Funktionen zur Verfügung, mit denen sie Werte ohne Einheiten in Werte mit Einheiten konvertieren können. Diese sind im Microsoft.FSharp.Core.LanguagePrimitives-Modul enthalten. Um beispielsweise von einem einheitslosen float in float<cm> zu konvertieren, verwenden Sie FloatWithMeasure, wie im folgenden Code gezeigt.

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

Maßeinheiten im F# Power Pack

Im F# Power Pack ist eine Einheitenbibliothek verfügbar. Die Einheitenbibliothek enthält SI-Einheiten und physikalische Konstanten.

Siehe auch

Weitere Ressourcen

F#-Sprachreferenz

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Mai 2010

Korrigiert Codebeispiel im Abschnitt "Konvertierungen".

Korrektur inhaltlicher Fehler.