Dela via


Null-värden

Det här avsnittet beskriver hur null-värdet används i F#.

Null-värden före F# 9

Null-värdet används normalt inte i F# för värden eller variabler. Null visas dock som ett onormalt värde i vissa situationer. Om en typ definieras i F#tillåts inte null som ett vanligt värde om inte attributet AllowNullLiteral tillämpas på typen. Om en typ definieras på något annat .NET-språk är null ett möjligt värde, och när du samverkar med sådana typer kan F#-koden stöta på null-värden.

För en typ som definierats i F# och används strikt från F#, är det enda sättet att skapa ett null-värde med hjälp av F#-biblioteket direkt att använda Unchecked.defaultof eller Array.zeroSkapa. Men för en F#-typ som används från andra .NET-språk, eller om du använder den typen med ett API som inte är skrivet i F#, till exempel .NET Framework, kan null-värden inträffa.

Du kan använda option typ i F# när du kan använda en referensvariabel med ett möjligt null-värde på ett annat .NET-språk. I stället för null, med en F#-option typ, använder du alternativvärdet None om det inte finns något objekt. Du använder alternativvärdet Some(obj) med ett objekt obj när det finns ett objekt. Mer information finns i Alternativ. Observera att du fortfarande kan packa ett null värde i ett Alternativ om x för Some xråkar vara null. Därför är det viktigt att du använder None när ett värde är null.

Nyckelordet null är ett giltigt nyckelord i F#, och du måste använda det när du arbetar med .NET Framework-API:er eller andra API:er som är skrivna på ett annat .NET-språk. De två situationer där du kan behöva ett null-värde är när du anropar ett .NET-API och skickar ett null-värde som ett argument, och när du tolkar returvärdet eller en utdataparameter från ett .NET-metodanrop.

Om du vill skicka ett null-värde till en .NET-metod använder du bara nyckelordet null i den anropande koden. Följande kodexempel illustrerar detta.

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

Om du vill tolka ett null-värde som hämtas från en .NET-metod använder du mönstermatchning om du kan. I följande kodexempel visas hur du använder mönstermatchning för att tolka null-värdet som returneras från ReadLine när det försöker läsa förbi slutet av en indataström.

// 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-värden för F#-typer kan också genereras på andra sätt, till exempel när du använder Array.zeroCreate, som anropar Unchecked.defaultof. Du måste vara försiktig med sådan kod för att behålla null-värdena inkapslade. I ett bibliotek som endast är avsett för F# behöver du inte söka efter null-värden i varje funktion. Om du skriver ett bibliotek för interoperation med andra .NET-språk kan du behöva lägga till kontroller för null-indataparametrar och utlösa en ArgumentNullException, precis som du gör i C# eller Visual Basic-kod.

Du kan använda följande kod för att kontrollera om ett godtyckligt värde är null.

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

Null-värden som börjar med F# 9

I F# 9 läggs extra funktioner till i språket för att hantera referenstyper som kan ha null som ett värde. De är inaktiverade som standard – för att aktivera dem måste följande egenskap placeras i projektfilen:

<Nullable>enable</Nullable>

Detta skickar --checknulls+-flaggan till F#-kompilatorn och anger ett NULLABLEförprocessordirektiv för byggprocessen.

Om du uttryckligen ska kunna välja null måste en typdeklaration vara suffixad med den nya syntaxen:

type | null

Stapelsymbolen | har innebörden av en logisk ELLER i syntaxen och skapar en union med två olika typer: den underliggande typen och den nullbara referensen. Detta är samma syntaktiska symbol som används för att deklarera flera fall av en F#-diskriminerad union: type AB = A | B bär innebörden av antingen Aeller B.

Den nullbara anteckningen | null kan användas på alla platser där en referenstyp normalt används:

  • Fält för unionstyper, rekordtyper och anpassade typer.
  • Skriv alias till befintliga typer.
  • Skriv program av allmän typ.
  • Explicita typanteckningar för att tillåta bindningar, parametrar eller returtyper.
  • Skriv anteckningar till objektprogrammeringskonstruktioner som medlemmar, egenskaper eller fält.
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 }

Stapelsymbolen | har andra användningar i F# som kan leda till syntaktiska tvetydigheter. I sådana fall behövs parenteser runt den null-annoterade typen.

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

Om du omsluter samma typ i ett par ( ) parenteser åtgärdas problemet:

type DUField = N of (string | null)

När | används i mönstermatchning, används det för att separera olika villkor.

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

Det här kodfragmentet motsvarar faktiskt kod som först utför ett typtest mot den string typen och sedan har en separat sats för hantering av null:

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

Viktig

De extra null-relaterade funktionerna har lagts till i språket i samverkanssyfte. Att använda | null i F#-typmodellering anses inte vara idiomatiskt för att beteckna information som saknas – för det ändamålet använder du alternativ (enligt beskrivningen ovan). Läs mer om null-relaterade konventioner i formatguiden.

Se även