Поиск…


замечания

Единицы во время выполнения

Единицы измерения используются только для статической проверки компилятором и не доступны во время выполнения. Они не могут использоваться в отражении или в методах, подобных ToString .

Например, C # дает double без единиц для поля типа float<m> определенного и отображаемого из библиотеки F #.

Обеспечение согласованных единиц в расчетах

Единицы измерения - это дополнительные аннотации типа, которые могут быть добавлены к поплавкам или целым числам. Они могут использоваться для проверки во время компиляции, когда расчеты используют единицы последовательно.

Чтобы определить аннотации:

[<Measure>] type m // meters
[<Measure>] type s // seconds
[<Measure>] type accel = m/s^2 // acceleration defined as meters per second squared

После определения аннотации могут использоваться для проверки того, что выражение приводит к ожидаемому типу.

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

Конверсии между единицами

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

Обратите внимание, что компилятор F # не знает, что 1<m> равно 100<cm> . Что касается этого, единицы являются отдельными типами. Вы можете написать аналогичные функции для преобразования от метров до килограммов, и компилятору все равно.

[<Measure>] type kg

// Valid code, invalid physics
let kgToM x = x / 100<kg/m>

Невозможно определить единицы измерения как кратность других единиц, таких как

// Invalid code
[<Measure>] type m = 100<cm>

Однако для определения единиц «за что-то», например, Герца, измеряя частоту, просто «в секунду», довольно просто.

// 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 для сохранения или установки единиц

Когда функция не сохраняет единицы автоматически из-за операций более низкого уровня, модуль LanguagePrimitives может использоваться для установки единиц на примитивах, которые их поддерживают:

/// This cast preserves units, while changing the underlying type
let inline castDoubleToSingle (x : float<'u>) : float32<'u> =
    LanguagePrimitives.Float32WithMeasure (float32 x)

Чтобы присвоить единицы измерения значению с плавающей запятой с двойной точностью, просто умножьте их на единицы с правильными единицами:

[<Measure>]
type USD

let toMoneyImprecise (amount : float) =
   amount * 1.<USD>

Чтобы присвоить единицы измерения единичному значению, которое не является System.Double, например, поступая из библиотеки, написанной на другом языке, используйте преобразование:

open LanguagePrimitives

let toMoney amount =
   amount |> DecimalWithMeasure<'u>

Ниже приведены типы функций, сообщенные F # interactive:

val toMoney : amount:decimal -> decimal<'u>
val toMoneyImprecise : amount:float -> float<USD>

Параметры типа единицы измерения

Атрибут [<Measure>] может использоваться для параметров типа для объявления типов, которые являются общими для единиц измерения:

type CylinderSize<[<Measure>] 'u> =
    { Radius : float<'u>
      Height : float<'u> }

Использование теста:

open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols

/// This has type CylinderSize<m>.
let testCylinder =
    { Radius = 14.<m>
      Height =  1.<m> }

Используйте стандартные типы устройств для обеспечения совместимости

Например, типы для единиц СИ были стандартизованы в основной библиотеке F # в Microsoft.FSharp.Data.UnitSystems.SI . Чтобы использовать их, откройте соответствующее пространство UnitNames , UnitNames или UnitSymbols . Или, если требуется только несколько единиц СИ, их можно импортировать с помощью псевдонимов типов:

/// Seconds, the SI unit of time. Type abbreviation for the Microsoft standardized type.
type [<Measure>] s = Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s

Некоторые пользователи имеют тенденцию делать следующее, что не должно выполняться всякий раз, когда определение уже доступно:

/// Seconds, the SI unit of time
type [<Measure>] s // DO NOT DO THIS! THIS IS AN EXAMPLE TO EXPLAIN A PROBLEM.

Разница становится очевидной при взаимодействии с другим кодом, который относится к стандартным типам SI. Код, который относится к стандартным единицам, совместим, а код, который определяет его собственный тип, несовместим с любым кодом, не использующим его конкретное определение.

Поэтому всегда используйте стандартные типы для единиц СИ. Не имеет значения, ссылаетесь ли вы на UnitNames или UnitSymbols , поскольку эквивалентные имена в этих двух относятся к одному типу:

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>


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow