2009-06-03 1 views
19

Каков правильный способ использования Nullable в F #?F #: Nullable <T> Поддержка

В настоящее время я использую это, но он кажется беспорядочным.

let test (left : Nullable<int>) = if left.HasValue then left.Value else 0 

Console.WriteLine(test (new System.Nullable<int>())) 
Console.WriteLine(test (new Nullable<int>(100))) 

let x = 100 
Console.WriteLine(test (new Nullable<int>(x))) 

ответ

17

Боится, что нет синтаксического сахара для обнуляемых типов в F # (в отличие от C#, где вы просто добавить в ? к типу). Так что да, код, который вы показываете там, выглядит ужасно подробным, но это единственный способ использовать тип System.Nullable<T> в F #.

Однако, я подозреваю, что вы действительно хотите использовать option types. Там в несколько достойных примеров на странице MSDN:

let keepIfPositive (a : int) = if a > 0 then Some(a) else None 

и

open System.IO 
let openFile filename = 
    try 
     let file = File.Open (filename, FileMode.Create) 
     Some(file) 
    with 
     | exc -> eprintf "An exception occurred with message %s" exc.Message; None 

Очевидно, что гораздо лучше использовать!

Опции по существу выполняют роль типов с нулевым значением в F #, и я должен думать, что вы действительно хотите использовать их, а не типы с нулевым значением (если только вы не взаимодействуете с C#). Разница в реализации заключается в том, что типы опций формируются с помощью дискриминационного объединения из Some(x) и None, тогда как Nullable<T> является нормальным классом в BCL с небольшим количеством синтаксического сахара в C#.

+0

Итак, как вы преобразовываете скаляр как 100 в "int option"? –

+0

Первый пример в моем сообщении показывает это. Для примера, который вы указали, это просто 'Some (100)' – Noldorin

+0

В настоящее время существует много синтаксической поддержки. См. Например, [все операторы, которые могут принимать значения с нулевым значением] (https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/nullable-operators), а также как функции «Option.ofNullable», «Option.toNullable» и многие другие. – Abel

12

Вы можете позволить F # вывести большинство типов там:

let test (left : _ Nullable) = if left.HasValue then left.Value else 0 

Console.WriteLine(test (Nullable())) 
Console.WriteLine(test (Nullable(100))) 

let x = 100 
Console.WriteLine(test (Nullable(x))) 

Вы можете также использовать active pattern применять сопоставление с образцом обнуляемых типов:

let (|Null|Value|) (x: _ Nullable) = 
    if x.HasValue then Value x.Value else Null 

let test = // this does exactly the same as the 'test' function above 
    function 
    | Value v -> v 
    | _ -> 0 

Я в блоге некоторое время назад о nullable types in F# [/ shameless_plug]

+0

Я только что это сделал. Вы можете объединить этот подход с серией Эрика Липперта по методам NULL-микрооптимизации (http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/) и использовать 'if n.HasValue, а затем n. GetValueOrDefault() else 0' вместо этого. – phoog

+0

@phoog Всякий раз, когда вы пишете «if n.HasValue», вы рискуете написать частичную функцию, поэтому лучше всего обернуть ее в исчерпывающий активный шаблон и всегда использовать это вместо этого. –

+0

Я не совсем понимаю. Вы говорите, что лучше * не * определять активный шаблон как 'let (| Null | Value |) (x: _ Nullable) = if x.HasValue then Value (x.GetValueOrDefault()) else Null'? – phoog