Megosztás a következőn keresztül:


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^3kö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/smé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^2rendszer.

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

Lásd még