Mértékegységek
Az F#-ban a lebegőpontos és az aláírt egész számokhoz kapcsolódó mértékegységek tartozhatnak, amelyek általában a hossz, a kötet, a tömeg stb. jelzésére szolgálnak. Ha mennyiségeket használ egységekkel, lehetővé teszi a fordító számára, hogy ellenőrizze, hogy az aritmetikai kapcsolatok megfelelő egységekkel rendelkeznek-e, ami segít megelőzni a programozási hibákat.
Feljegyzés
Ezek a példák a mértékegységeket tartalmazó aritmetikai számítások helyességét mutatják be. A funkció felhasználható a típusbiztos széljegyzetek más típusokhoz való zéró megjelenítési költségekkel való hozzáadásához is, például FSharp.UMX-projekttel .
Syntax
[<Measure>] type unit-name [ = measure ]
Megjegyzések
Az előző szintaxis mértékegységként definiálja az egységnevet . Az opcionális rész egy új mérték definiálására szolgál a korábban definiált egységek tekintetében. Az alábbi sor például a mértéket cm
(centimétert) határozza meg.
[<Measure>] type cm
Az alábbi sor a mértéket ml
(millilitert) köb centiméterként (cm^3
köbméterként) határozza meg.
[<Measure>] type ml = cm^3
Az előző szintaxisban a mérték egy mértékegységet tartalmazó képlet. Az egységeket tartalmazó képletekben az integrálerők támogatottak (pozitívak és negatívak), az egységek közötti szóközök a két egység szorzatát jelölik, *
az egységek szorzatát, valamint /
az egységek hányadosát. A reciprokegységek esetében használhat negatív egész számot, vagy olyan /
értéket, amely egy egységképlet számlálója és nevezője közötti elkülönítést jelzi. A nevezőben lévő több egységet zárójelekkel kell körülvenni. Az egy /
után szóközzel elválasztott egységeket a nevező részeként értelmezik, az a *
következő egységeket azonban a számláló részeként értelmezik.
Az 1-et használhatja egységkifejezésekben, akár csak dimenzió nélküli mennyiség jelzésére, akár más mértékegységekkel együtt, például a számlálóban. A ráta 1/s
mértékegysége például a másodpercet jelzi.s
A zárójelek nem használhatók egységképletekben. A számkonvertálási állandókat nem adja meg az egységképletekben; Az egységekkel rendelkező konverziós állandókat azonban külön-külön definiálhatja, és felhasználhatja őket az egységellenőrzésű számításokban.
Az egységképletek, amelyek ugyanazt jelentik, különböző egyenértékű módon írhatók. A fordító ezért konzisztens formává alakítja az egységképleteket, amely a negatív erőket reciprokká alakítja, az egységeket egyetlen számlálóvá és nevezővé csoportosítja, és betűrendbe rendezi a számlálóban és a nevezőben lévő egységeket.
Például az egységképletek kg m s^-2
, és m /s s * kg
mindkettőt átalakítja a kg m/s^2
rendszer.
Mértékegységeket használ a lebegőpontos kifejezésekben. A lebegőpontos számok és a hozzájuk tartozó mértékegységek együttes használata a típusbiztonság egy újabb szintjét növeli, és segít elkerülni a képletekben gyenge beírású lebegőpontos számok használatakor előforduló egységeltérési hibákat. Ha mértékegységeket használó lebegőpontos kifejezést ír, a kifejezésben szereplő egységeknek egyeznie kell.
A literálokat szögletes zárójelekben lévő egységképlettel is megjegyzésekkel láthatja el, ahogyan az alábbi példákban is látható.
1.0<cm>
55.0<miles/hour>
Ne tegyen szóközt a szám és a szögletes zárójel közé; azonban egy literális utótagot is megadhat, például f
az alábbi példában.
// The f indicates single-precision floating point.
55.0f<miles/hour>
Az ilyen széljegyzetek a literál típusát a primitív típusról (például float
) dimenziós típusra módosítják, például float<cm>
ebben az esetben float<miles/hour>
. Az egységjegyzet <1>
dimenzió nélküli mennyiséget jelez, és típusa egyenértékű az egységparaméter nélküli primitív típussal.
A mértékegység típusa egy lebegőpontos vagy aláírt integráltípus, valamint egy plusz egységjegyzet, szögletes zárójelben jelezve. Így, amikor megírja a (gramm) g
és a (kilogramm) kg
közötti átalakítás típusát, az alábbiak szerint írja le a típusokat.
let convertg2kg (x : float<g>) = x / 1000.0<g/kg>
A mértékegységek a fordítási időegység-ellenőrzéshez használatosak, de a futásidejű környezetben nem maradnak meg. Ezért nem befolyásolják a teljesítményt.
A mértékegységek bármilyen típusra alkalmazhatók, nem csak lebegőpontos típusokra; azonban csak a lebegőpontos típusok, az aláírt integráltípusok és a decimális típusok támogatják a dimenziós mennyiségeket. Ezért csak a primitív típusokra és az ezeket a primitív típusokat tartalmazó aggregátumokra érdemes mértékegységeket használni.
Az alábbi példa a mértékegységek használatát mutatja be.
// 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
Az alábbi példakód bemutatja, hogyan konvertálható dimenzió nélküli lebegőpontos számból dimenziózott lebegőpontos értékké. Csak szorozza meg az 1,0-t, és alkalmazza a dimenziókat az 1,0-ra. Ezt egy olyan függvényre is absztraktálhatja, mint a degreesFahrenheit
.
Ha dimenziózott értékeket ad át a dimenzió nélküli lebegőpontos számokat váró függvények számára, az operátorral le kell mondania az egységeket, vagy át kell adnia float
azokat float
. Ebben a példában az argumentumok printf
szerint 1.0<degC>
osztunk, mert printf
dimenzió nélküli mennyiségre számítunk.
[<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."
Az alábbi példamunkamenet a kód kimeneteit és bemeneteit mutatja be.
Enter a temperature in degrees Fahrenheit.
90
That temperature in degrees Celsius is 32.22.
A mértékegységeket támogató primitív típusok
A következő típus- vagy típus rövidítési aliasok a mértékegységek megjegyzéseit támogatják:
F# alias | CLR-típus |
---|---|
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 |
Egy aláíratlan egész számot például az alábbiak szerint jegyzetelhet:
[<Measure>]
type days
let better_age = 3u<days>
Az aláíratlan egész számtípusok hozzáadása ehhez a funkcióhoz az F# RFC FS-1091-ben dokumentálva van.
Előre definiált mértékegységek
A névtérben FSharp.Data.UnitSystems.SI
elérhető egy egységkódtár. Az SI-egységeket a szimbólum formájában (például m
mérő) az UnitSymbols
alnévtérben, a teljes nevükben (mint például meter
a mérő) tartalmazza az UnitNames
alnévtérben.
Általános egységek használata
Olyan általános függvényeket írhat, amelyek egy társított mértékegységet tartalmazó adatokon működnek. Ezt úgy teheti meg, hogy egy típust egy általános egységgel együtt ad meg típusparaméterként, ahogyan az az alábbi kód példájában is látható.
// 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
Gyűjteménytípusok létrehozása általános egységekkel
Az alábbi kód bemutatja, hogyan hozhat létre összesített típust, amely általános mértékegységekkel rendelkező egyedi lebegőpontos értékekből áll. Ez lehetővé teszi egyetlen típus létrehozását, amely számos különböző egységhez használható. Emellett az általános egységek megőrzik a típusbiztonságot azáltal, hogy biztosítják, hogy egy olyan általános típus, amely egy egységkészlettel rendelkezik, más típusú legyen, mint ugyanaz az általános típus, és egy másik egységkészlettel. Ennek a technikának az alapja, hogy az Measure
attribútum alkalmazható a típusparaméterre.
// 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> }
Egységek a futtatókörnyezetben
A mértékegységek statikus típusellenőrzéshez használatosak. A lebegőpontos értékek lefordításakor a mértékegységek megszűnnek, így az egységek futásidőben elvesznek. Ezért nem lehet olyan funkciókat implementálni, amelyek az egységek futásidőben történő ellenőrzésén alapulnak. Például nem lehet függvényt ToString
implementálni az egységek nyomtatásához.
Konverziók
Ha egy egységeket tartalmazó típust (például ) olyan típussá szeretne konvertálni, float<'u>
amely nem tartalmaz egységeket, használhatja a standard konverziós függvényt. Például olyan értékké float
alakítható float
át, amely nem tartalmaz egységeket, ahogy az az alábbi kódban is látható.
[<Measure>]
type cm
let length = 12.0<cm>
let x = float length
Ha egység nélküli értéket szeretne egységekkel rendelkező értékké alakítani, megszorozhatja a megfelelő egységekkel jegyzett 1 vagy 1,0 értéket. Az együttműködési rétegek írásához azonban bizonyos explicit függvények is használhatók az egység nélküli értékek egységekkel való átalakításához. Ezek az FSharp.Core.LanguagePrimitives modulban találhatók. Ha például egység nélküliről float
egy floatWithMeasure-ra szeretne konvertálni float<cm>
, használja a FloatWithMeasure parancsot, ahogyan az az alábbi kódban látható.
open Microsoft.FSharp.Core
let height:float<cm> = LanguagePrimitives.FloatWithMeasure x