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 x
rå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 NULLABLE
fö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 A
eller 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.