Поделиться через


Значения NULL

В этом разделе описывается, как значение NULL используется в F#.

Значения NULL до F# 9

Значение NULL обычно не используется в F# для значений или переменных. Однако значение NULL появляется как ненормальное значение в определенных ситуациях. Если тип определен в F#, значение null не допускается как регулярное значение, если к типу не применяется атрибут AllowNullLiteral. Если тип определен в другом языке .NET, значение NULL возможно, и при взаимодействии с такими типами код F# может столкнуться со значениями NULL.

Для типа, определенного в F# и используемого строго в контексте F#, единственный способ создать значение null, используя библиотеку F# напрямую, заключается в применении Unchecked.defaultof или Array.zeroCreate. Однако для типа F#, используемого на других языках .NET, или если вы используете этот тип с API, который не написан в F#, например .NET Framework, могут возникать значения NULL.

Тип option в F# можно использовать, если можно использовать эталонную переменную с возможным значением NULL на другом языке .NET. Вместо null с типом F# option используется значение параметра None, если нет объекта. Значение параметра Some(obj) используется с объектом obj при наличии объекта. Дополнительные сведения см. в опциях. Обратите внимание, что вы по-прежнему можете упаковать значение null в Option, если для Some xx оказывается null. Из-за этого важно использовать None, когда значение null.

Ключевое слово null является допустимым ключевым словом в F#, и его необходимо использовать при работе с API .NET Framework или другими API, написанными на другом языке .NET. Две ситуации, в которых может потребоваться значение NULL, возникают при вызове API .NET и передаче значения NULL в качестве аргумента, а также при интерпретации возвращаемого значения или выходного параметра из вызова метода .NET.

Чтобы передать значение NULL в метод .NET, просто используйте ключевое слово null в вызывающем коде. В следующем примере кода показано следующее.

open System

// Pass a null value to a .NET method.
let ParseDateTime (str: string) =
    let (success, res) =
        DateTime.TryParse(str, null, System.Globalization.DateTimeStyles.AssumeUniversal)

    if success then Some(res) else None

Чтобы интерпретировать значение NULL, полученное из метода .NET, используйте сопоставление шаблонов, если это возможно. В следующем примере кода показано, как использовать сопоставление шаблонов для интерпретации значения NULL, возвращаемого из ReadLine при попытке прочитать после конца входного потока.

// Open a file and create a stream reader.
let fileStream1 =
    try
        System.IO.File.OpenRead("TextFile1.txt")
    with :? System.IO.FileNotFoundException ->
        printfn "Error: TextFile1.txt not found."
        exit (1)

let streamReader = new System.IO.StreamReader(fileStream1)

// ProcessNextLine returns false when there is no more input;
// it returns true when there is more input.
let ProcessNextLine nextLine =
    match nextLine with
    | null -> false
    | inputString ->
        match ParseDateTime inputString with
        | Some(date) -> printfn "%s" (date.ToLocalTime().ToString())
        | None -> printfn "Failed to parse the input."

        true

// A null value returned from .NET method ReadLine when there is
// no more input.
while ProcessNextLine(streamReader.ReadLine()) do
    ()

Значения NULL для типов F# также могут быть сгенерированы другими способами, например, когда используется Array.zeroCreate, который вызывает Unchecked.defaultof. Для сохранения инкапсулированных значений null необходимо тщательно использовать такой код. В библиотеке, предназначенной только для F#, не требуется проверять наличие значений NULL в каждой функции. Если вы пишете библиотеку для взаимодействия с другими языками .NET, может потребоваться добавить проверки для параметров ввода null и создать ArgumentNullExceptionтак же, как и в коде C# или Visual Basic.

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

match box value with
| null -> printf "The value is null."
| _ -> printf "The value is not null."

Значения NULL, начиная с F# 9

В F# 9 в язык добавляются дополнительные возможности для работы с ссылочными типами, которые могут принимать значение null. Они отключены по умолчанию. Чтобы включить их, в файл проекта необходимо поместить следующее свойство:

<Nullable>enable</Nullable>

Это передает флаг --checknulls+ компилятору F# и задает директиву препроцессора NULLABLE для сборки.

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

type | null

Символ строки | имеет значение логического ИЛИ в синтаксисе, создавая объединение двух несвязанных наборов типов: базовый тип и ссылку на значение NULL. Это тот же синтаксический символ, который используется для объявления нескольких случаев дискриминированного объединения F#: type AB = A | B имеет значение либо A, либо B.

Аннотация для значения NULL | null может использоваться во всех местах, где обычно применяется ссылочный тип.

  • Поля типов объединения, типов записей и пользовательских типов.
  • Псевдонимы типов для существующих типов.
  • Тип приложений универсального типа.
  • Явные аннотации типов для связываний, параметров или возвращаемых типов.
  • Введите заметки к конструкциям объектного программирования, таким как элементы, свойства или поля.
type AB = A | B
type AbNull = AB | null

type RecordField = { X: string | null }
type TupleField = string * string | null

type NestedGenerics = { Z : List<List<string | null> | null> | null }

Символ строки | имеет другие способы использования в F#, что может привести к синтаксической неоднозначности. В таких случаях круглые скобки требуются вокруг аннотированного типа null:

// Unexpected symbol '|' (directly before 'null') in member definition
type DUField = N of string | null

Обёртывание одного и того же типа в пары круглых скобок ( ) устраняет проблему.

type DUField = N of (string | null)

При использовании в сопоставлении шаблонов | используется для разделения различных условий сопоставления шаблонов.

match x with
| ?: string | null -> ...

Этот фрагмент фактически эквивалентен тому, что код сначала выполняет проверку типа для типа string, а затем содержит отдельное условие для обработки null.

match x with
| ?: string 
| null -> ...

Важный

Дополнительные возможности, связанные с null, были добавлены на язык для целей взаимодействия. Использование | null в моделировании типов F# не считается идиоматичным для обозначения отсутствующих сведений — для этой цели используйте параметры (как описано выше). Узнайте больше о соглашениях, связанных с NULL, в руководстве по стилю.

См. также