Null 值
本主題描述如何在 F# 中使用 Null 值。
F# 9 之前的 Null 值
Null 值通常不會用於 F# 中的值或變數。 不過,在某些情況下,Null 會顯示為異常值。 如果類型是在 F# 中定義,除非將 AllowNullLiteral 屬性套用至類型,否則不允許 null 做為一般值。 如果類型是以其他 .NET 語言定義,則 Null 是可能的值,而且當您與這類類型互通時,F# 程式代碼可能會遇到 Null 值。
對於在 F# 中定義的類型,並且嚴格使用 F# 使用,直接 使用 F# 連結庫建立 Null 值的唯一方法是使用 unchecked.defaultof 或 Array.zeroCreate。 不過,對於來自其他 .NET 語言使用的 F# 類型,或如果您使用該類型搭配未以 F# 撰寫的 API,例如 .NET Framework,就可能發生 Null 值。
在其他 .NET 語言中使用可能包含 Null 值的參考變數時,在 F# 中可以使用 option
類型。 在 F# option
類型中,如果沒有物件,你應該使用選項值 None
。 當有物件時,您應搭配物件 obj
使用選項值 Some(obj)
。 如需詳細資訊,請參閱 選項。 請注意,如果 Some x
,您仍然可以將 null
值封裝到 Option 中,x
恰好 null
。 因此,當值 null
時,請務必使用 None
。
null
關鍵詞是 F# 中的有效關鍵詞,當您使用以其他 .NET 語言撰寫的 .NET Framework API 或其他 API 時,您必須使用它。 當您在呼叫 .NET API 時,可能需要使用空值的兩種情況是:一是將空值作為引數傳遞,二是解釋 .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
若要解譯從 .NET 方法取得的 Null 值,如果可以的話,請使用模式比對。 下列程式代碼範例示範如何使用模式比對來解譯從 ReadLine
傳回的 null 值,當它嘗試讀取到輸入數據流結尾時。
// 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
()
F# 類型的 Null 值也可以透過其他方式產生,例如當您使用 Array.zeroCreate
時,它會呼叫 Unchecked.defaultof
。 您必須小心使用這類程式碼,以保持空值被封裝。 在僅供 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."
從 F# 9 開始的 Null 值
在 F# 9 中,語言新增了額外的功能來處理可以將 null
作為值的參考型別。 這些預設為關閉 - 若要開啟它們,必須將下列屬性放在您的項目檔中:
<Nullable>enable</Nullable>
這會將 --checknulls+
旗標 傳遞至 F# 編譯程式,併為組建設定 NULLABLE
預處理器指示詞。
若要明確地選擇支援可為 Null 的特性,必須在類型宣告中添加新的語法後綴:
type | null
條形符號 |
在語法中表示邏輯 OR,它構建了兩個不相交的類型集合的聯集:基礎類型和可空引用。 這是相同的語法記號,用於宣告 F# 歧視聯集的多種類型:type AB = A | B
具有 A
或 B
的意義。
可為 Null 的註解 | null
可用於通常使用參考型別的所有位置:
- 等位類型、記錄類型和自定義類型的欄位。
- 為現有類型創建的別名。
- 泛型型別的類型應用程式。
- 對 let 綁定、參數或回傳型別添加明確的型別註解。
- 將型別標註應用於物件導向程式設計的結構,例如成員、屬性或欄位。
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# 中有其他用法,這可能會導致語法模棱兩可。 在這種情況下,在註記為空的型別周圍需要括號:
// 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 相關功能已新增至語言,以達到互操作性的目的。 在 F# 類型建模中使用 | null
並不被認為是表示遺漏資訊的慣常做法,為了達到這個目的,請使用選項(如上所述)。 若要深入瞭解與 null 相關的 慣例,請參閱樣式指南中的。