測量單位Units of Measure

中的浮點數和帶正負F#號的整數值可以具有相關聯的測量單位, 通常用來表示長度、數量、品質等等。Floating point and signed integer values in F# can have associated units of measure, which are typically used to indicate length, volume, mass, and so on. 藉由使用具有單位的數量, 您可以讓編譯器驗證算術關聯性是否有正確的單位, 這有助於防止程式設計錯誤。By using quantities with units, you enable the compiler to verify that arithmetic relationships have the correct units, which helps prevent programming errors.

語法Syntax

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

備註Remarks

先前的語法會將單位名稱定義為量值單位。The previous syntax defines unit-name as a unit of measure. 選擇性部分是用來根據先前定義的單位來定義新的量值。The optional part is used to define a new measure in terms of previously defined units. 例如, 下列程式程式碼會定義量值cm (釐米)。For example, the following line defines the measure cm (centimeter).

[<Measure>] type cm

下一行會將量值ml (milliliter) 定義為三釐米 (cm^3)。The following line defines the measure ml (milliliter) as a cubic centimeter (cm^3).

[<Measure>] type ml = cm^3

在先前的語法中, measure是包含單位的公式。In the previous syntax, measure is a formula that involves units. 在牽涉到單位的公式中, 整數類支援 (正和負數)、單位之間的空格表示兩個單位的產品* , 也表示單位的乘積, 並/指出單位的商。In formulas that involve units, integral powers are supported (positive and negative), spaces between units indicate a product of the two units, * also indicates a product of units, and / indicates a quotient of units. 針對交互單位, 您可以使用負整數乘冪或/ , 表示單位公式的分子和分母之間的分隔。For a reciprocal unit, you can either use a negative integer power or a / that indicates a separation between the numerator and denominator of a unit formula. 分母中的多個單位應該以括弧括住。Multiple units in the denominator should be surrounded by parentheses. 以空格/分隔的單位會解讀為分母的一部分, 但*後面的任何單位都會被視為分子的一部分。Units separated by spaces after a / are interpreted as being part of the denominator, but any units following a * are interpreted as being part of the numerator.

您可以在單位運算式中使用1來表示量維度數量, 或與其他單位 (例如分子) 一起使用。You can use 1 in unit expressions, either alone to indicate a dimensionless quantity, or together with other units, such as in the numerator. 例如, 速率的單位會寫成1/s, 其中s表示秒數。For example, the units for a rate would be written as 1/s, where s indicates seconds. 單元公式中不使用括弧。Parentheses are not used in unit formulas. 您不會在單元公式中指定數值轉換常數;不過, 您可以分別使用單位來定義轉換常數, 並在單元檢查計算中使用它們。You do not specify numeric conversion constants in the unit formulas; however, you can define conversion constants with units separately and use them in unit-checked computations.

表示相同事物的單位公式可以用各種同等的方式撰寫。Unit formulas that mean the same thing can be written in various equivalent ways. 因此, 編譯器會將單元公式轉換成一致的形式, 將負冪轉換成 reciprocals、將單位群組成單一分子和分母, 然後 Alphabetizes 分子和分母中的單位。Therefore, the compiler converts unit formulas into a consistent form, which converts negative powers to reciprocals, groups units into a single numerator and a denominator, and alphabetizes the units in the numerator and denominator.

例如, 單位公式kg m s^-2m /s s * kg都會轉換成kg m/s^2For example, the unit formulas kg m s^-2 and m /s s * kg are both converted to kg m/s^2.

您在浮點運算式中使用量值單位。You use units of measure in floating point expressions. 使用浮點數搭配相關聯的測量單位, 會增加另一層的型別安全, 並協助避免當您使用弱式類型的浮點數時, 公式中可能發生的單位不相符錯誤。Using floating point numbers together with associated units of measure adds another level of type safety and helps avoid the unit mismatch errors that can occur in formulas when you use weakly typed floating point numbers. 如果您撰寫使用單位的浮點運算式, 則運算式中的單位必須相符。If you write a floating point expression that uses units, the units in the expression must match.

您可以使用單元公式以角括弧標注常值, 如下列範例所示。You can annotate literals with a unit formula in angle brackets, as shown in the following examples.

1.0<cm>
55.0<miles/hour>

您不會在數位和角括弧之間加上空格。不過, 您可以包含常值尾碼f, 例如, 如下列範例所示。You do not put a space between the number and the angle bracket; however, you can include a literal suffix such as f, as in the following example.

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

這類注釋會將常值的類型從其基本類型 (例如float) 變更為維度類型, float<cm>例如或float<miles/hour>, 在此案例中為。Such an annotation changes the type of the literal from its primitive type (such as float) to a dimensioned type, such as float<cm> or, in this case, float<miles/hour>. <1>單位注釋表示量維度數量, 而其類型等同于不含 unit 參數的基本型別。A unit annotation of <1> indicates a dimensionless quantity, and its type is equivalent to the primitive type without a unit parameter.

量值單位的類型是一個浮點數或帶正負號的整數類資料類型, 以及一個額外的單位注釋, 以方括弧表示。The type of a unit of measure is a floating point or signed integral type together with an extra unit annotation, indicated in brackets. 因此, 當您將轉換類型從g (克kg ) 寫入 (千克) 時, 您會依照下列方式描述類型。Thus, when you write the type of a conversion from g (grams) to kg (kilograms), you describe the types as follows.

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

測量單位用於編譯時間單元檢查, 但不會保存在執行時間環境中。Units of measure are used for compile-time unit checking but are not persisted in the run-time environment. 因此, 它們不會影響效能。Therefore, they do not affect performance.

量值單位可以套用至任何類型, 而不只是浮點數類型。不過, 只有浮點類型、帶正負號的整數類資料類型和十進位類型支援維度數量。Units of measure can be applied to any type, not just floating point types; however, only floating point types, signed integral types, and decimal types support dimensioned quantities. 因此, 在基本型別和包含這些基本型別的匯總上使用測量單位是合理的。Therefore, it only makes sense to use units of measure on the primitive types and on aggregates that contain these primitive types.

下列範例說明測量單位的使用。The following example illustrates the use of units of measure.

// 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

下列程式碼範例說明如何從量值浮點數轉換為已維度的浮點數。The following code example illustrates how to convert from a dimensionless floating point number to a dimensioned floating point value. 您只要乘以 1.0, 就會將維度套用至1.0。You just multiply by 1.0, applying the dimensions to the 1.0. 您可以將此抽象成類似degreesFahrenheit的函式。You can abstract this into a function like degreesFahrenheit.

此外, 當您將已維度的值傳遞給預期會有量維度浮點數的函式時, 您必須float float使用運算子取消單位或轉換成。Also, when you pass dimensioned values to functions that expect dimensionless floating point numbers, you must cancel out the units or cast to float by using the float operator. 在此範例中, 您會1.0<degC>將的printf引數除以printf , 因為需要量維度數量。In this example, you divide by 1.0<degC> for the arguments to printf because printf expects dimensionless quantities.

[<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."

下列範例會話會顯示此程式碼的輸出和輸入。The following example session shows the outputs from and inputs to this code.

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

使用泛型單位Using Generic Units

您可以撰寫可在具有相關聯測量單位的資料上運作的泛型函數。You can write generic functions that operate on data that has an associated unit of measure. 若要這麼做, 您可以將類型與一般單位一起指定為類型參數, 如下列程式碼範例所示。You do this by specifying a type together with a generic unit as a type parameter, as shown in the following code example.

// 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

建立具有泛型單位的匯總類型Creating Aggregate Types with Generic Units

下列程式碼示範如何建立匯總類型, 其中包含具有泛型單位的個別浮點值。The following code shows how to create an aggregate type that consists of individual floating point values that have units that are generic. 這可讓您建立單一類型, 以搭配各種單位使用。This enables a single type to be created that works with a variety of units. 此外, 一般單位會藉由確保具有一組單位的泛型型別與具有不同單位集合的相同泛型型別不同, 來保留型別安全。Also, generic units preserve type safety by ensuring that a generic type that has one set of units is a different type than the same generic type with a different set of units. 這項技術的基礎是Measure可以將屬性套用至型別參數。The basis of this technique is that the Measure attribute can be applied to the type parameter.

 // 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> }

執行時間的單位Units at Runtime

測量單位用於靜態類型檢查。Units of measure are used for static type checking. 當您編譯浮點值時, 測量單位會被排除, 因此在執行時間會遺失單位。When floating point values are compiled, the units of measure are eliminated, so the units are lost at run time. 因此, 任何嘗試執行的功能, 都不可能發生于檢查執行時間的單位。Therefore, any attempt to implement functionality that depends on checking the units at run time is not possible. 例如, 不可能執行ToString函數來列印單位。For example, implementing a ToString function to print out the units is not possible.

轉換Conversions

若要將具有單位 (例如float<'u>) 的類型轉換成不具有單位的類型, 您可以使用標準轉換函數。To convert a type that has units (for example, float<'u>) to a type that does not have units, you can use the standard conversion function. 例如, 您可以使用float將轉換float成沒有單位的值, 如下列程式碼所示。For example, you can use float to convert to a float value that does not have units, as shown in the following code.

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

若要將未使用的值轉換為具有單位的值, 您可以乘以以適當單位標注的1或1.0 值。To convert a unitless value to a value that has units, you can multiply by a 1 or 1.0 value that is annotated with the appropriate units. 不過, 若要撰寫互通性層, 還有一些明確的函式, 可讓您用來將沒有單位的值轉換成值。However, for writing interoperability layers, there are also some explicit functions that you can use to convert unitless values to values with units. 這些是在languageprimitives.physicalequality模組中。These are in the Microsoft.FSharp.Core.LanguagePrimitives module. 例如, 若要從float無單位的轉換float<cm>為, 請使用FloatWithMeasure, 如下列程式碼所示。For example, to convert from a unitless float to a float<cm>, use FloatWithMeasure, as shown in the following code.

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

F#核心程式庫中的測量單位Units of Measure in the F# Core library

FSharp.Data.UnitSystems.SI命名空間中可以使用單位程式庫。A unit library is available in the FSharp.Data.UnitSystems.SI namespace. m它在UnitSymbols子命名空間中的符號形式 (例如 for 計量) 中包含 SI 單位, 而在UnitNames子命名空間中, meter其完整名稱 (例如 for 計量)。It includes SI units in both their symbol form (like m for meter) in the UnitSymbols sub-namespace, and their full name (like meter for meter) in the UnitNames sub-namespace.

另請參閱See also