Zoeken…
Opmerkingen
Eenheden tijdens runtime
Maateenheden worden alleen gebruikt voor statische controle door de compiler en zijn niet beschikbaar tijdens runtime. Ze kunnen niet worden gebruikt in reflectie of in methoden zoals ToString
.
C # geeft bijvoorbeeld een double
zonder eenheden voor een veld van type float<m>
gedefinieerd door en blootgesteld vanuit een F # bibliotheek.
Zorgen voor consistente eenheden in berekeningen
Maateenheden zijn aanvullende type-annotaties die kunnen worden toegevoegd aan floats of gehele getallen. Ze kunnen worden gebruikt om tijdens het compileren te verifiëren dat berekeningen consistent eenheden gebruiken.
Aantekeningen definiëren:
[<Measure>] type m // meters
[<Measure>] type s // seconds
[<Measure>] type accel = m/s^2 // acceleration defined as meters per second squared
Eenmaal gedefinieerd, kunnen annotaties worden gebruikt om te verifiëren dat een uitdrukking het verwachte type oplevert.
// Compile-time checking that this function will return meters, since (m/s^2) * (s^2) -> m
// Therefore we know units were used properly in the calculation.
let freeFallDistance (time:float<s>) : float<m> =
0.5 * 9.8<accel> * (time*time)
// It is also made explicit at the call site, so we know that the parameter passed should be in seconds
let dist:float<m> = freeFallDistance 3.0<s>
printfn "%f" dist
Conversies tussen eenheden
[<Measure>] type m // meters
[<Measure>] type cm // centimeters
// Conversion factor
let cmInM = 100<cm/m>
let distanceInM = 1<m>
let distanceInCM = distanceInM * cmInM // 100<cm>
// Conversion function
let cmToM (x : int<cm>) = x / 100<cm/m>
let mToCm (x : int<m>) = x * 100<cm/m>
cmToM 100<cm> // 1<m>
mToCm 1<m> // 100<cm>
Merk op dat de F # compiler niet weet dat 1<m>
gelijk is aan 100<cm>
. Wat de zorg betreft, zijn de eenheden afzonderlijke typen. U kunt vergelijkbare functies schrijven om te converteren van meters naar kilo's, en de compiler maakt het niet uit.
[<Measure>] type kg
// Valid code, invalid physics
let kgToM x = x / 100<kg/m>
Het is niet mogelijk om maateenheden te definiëren als veelvouden van andere eenheden zoals
// Invalid code
[<Measure>] type m = 100<cm>
Het is echter vrij eenvoudig om eenheden "per iets", bijvoorbeeld Hertz, de frequentie te definiëren, eenvoudig "per seconde" te definiëren.
// Valid code
[<Measure>] type s
[<Measure>] type Hz = /s
1 / 1<s> = 1 <Hz> // Evaluates to true
[<Measure>] type N = kg m/s // Newtons, measuring force. Note lack of multiplication sign.
// Usage
let mass = 1<kg>
let distance = 1<m>
let time = 1<s>
let force = mass * distance / time // Evaluates to 1<kg m/s>
force = 1<N> // Evaluates to true
LanguagePrimitives gebruiken om eenheden te behouden of in te stellen
Als een functie eenheden niet automatisch bewaart als gevolg van bewerkingen op een lager niveau, kan de LanguagePrimitives
module worden gebruikt om eenheden in te stellen op de primitieven die hen ondersteunen:
/// This cast preserves units, while changing the underlying type
let inline castDoubleToSingle (x : float<'u>) : float32<'u> =
LanguagePrimitives.Float32WithMeasure (float32 x)
Om maateenheden toe te wijzen aan een drijvende-kommawaarde met dubbele precisie, vermenigvuldigt u eenvoudig met één met de juiste eenheden:
[<Measure>]
type USD
let toMoneyImprecise (amount : float) =
amount * 1.<USD>
Om maateenheden toe te wijzen aan een eenheidloze waarde die geen systeem is. Dubbel, bijvoorbeeld vanuit een bibliotheek geschreven in een andere taal, gebruikt u een conversie:
open LanguagePrimitives
let toMoney amount =
amount |> DecimalWithMeasure<'u>
Dit zijn de functietypen die worden gerapporteerd door F # interactive:
val toMoney : amount:decimal -> decimal<'u>
val toMoneyImprecise : amount:float -> float<USD>
Parameters van het maateenheidtype
Het kenmerk [<Measure>]
kan op typeparameters worden gebruikt om typen aan te geven die generiek zijn met betrekking tot meeteenheden:
type CylinderSize<[<Measure>] 'u> =
{ Radius : float<'u>
Height : float<'u> }
Test gebruik:
open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols
/// This has type CylinderSize<m>.
let testCylinder =
{ Radius = 14.<m>
Height = 1.<m> }
Gebruik gestandaardiseerde eenheidstypen om de compatibiliteit te behouden
Typen voor SI-eenheden zijn bijvoorbeeld gestandaardiseerd in de F # core-bibliotheek, in Microsoft.FSharp.Data.UnitSystems.SI
. Open de juiste UnitNames
, UnitNames
of UnitSymbols
om ze te gebruiken. Of, als slechts enkele SI-eenheden nodig zijn, kunnen deze worden geïmporteerd met type-aliassen:
/// Seconds, the SI unit of time. Type abbreviation for the Microsoft standardized type.
type [<Measure>] s = Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s
Sommige gebruikers hebben de neiging om het volgende te doen, wat niet zou moeten gebeuren wanneer er al een definitie beschikbaar is:
/// Seconds, the SI unit of time
type [<Measure>] s // DO NOT DO THIS! THIS IS AN EXAMPLE TO EXPLAIN A PROBLEM.
Het verschil wordt duidelijk wanneer het wordt gekoppeld aan andere code die verwijst naar de standaard SI-typen. Code die verwijst naar de standaardeenheden is compatibel, terwijl code die het eigen type definieert, niet compatibel is met code die geen specifieke definitie gebruikt.
Gebruik daarom altijd de standaardtypen voor SI-eenheden. Het maakt niet uit of u verwijst naar UnitNames
of UnitSymbols
, omdat equivalente namen binnen die twee naar hetzelfde type verwijzen:
open Microsoft.FSharp.Data.UnitSystems.SI
/// This is valid, since both versions refer to the same authoritative type.
let validSubtraction = 1.<UnitSymbols.s> - 0.5<UnitNames.second>