Opcje
Typ opcji w języku F# jest używany, gdy rzeczywista wartość może nie istnieć dla nazwanej wartości lub zmiennej. Opcja ma typ bazowy i może przechowywać wartość tego typu lub może nie mieć wartości.
Uwagi
Poniższy kod ilustruje funkcję, która generuje typ opcji.
let keepIfPositive (a: int) = if a > 0 then Some(a) else None
Jak widać, jeśli wartość a
przekracza 0, Some(a)
jest generowane. W przeciwnym razie jest generowany None
.
Wartość None
jest używana, gdy opcja nie ma rzeczywistej wartości. W przeciwnym razie wyrażenie Some( ... )
przypisuje wartości opcji. Wartości Some
i None
są przydatne w dopasowywaniu wzorców, jak w poniższej funkcji exists
, która zwraca true
, jeśli opcja ma wartość i false
, jeśli nie.
let exists (x: int option) =
match x with
| Some(x) -> true
| None -> false
Korzystanie z opcji
Opcje są często używane, gdy wyszukiwanie nie zwraca pasującego wyniku, jak pokazano w poniższym kodzie.
let rec tryFindMatch pred list =
match list with
| head :: tail -> if pred (head) then Some(head) else tryFindMatch pred tail
| [] -> None
// result1 is Some 100 and its type is int option.
let result1 = tryFindMatch (fun elem -> elem = 100) [ 200; 100; 50; 25 ]
// result2 is None and its type is int option.
let result2 = tryFindMatch (fun elem -> elem = 26) [ 200; 100; 50; 25 ]
W poprzednim kodzie lista jest wyszukiwana rekursywnie. Funkcja tryFindMatch
przyjmuje funkcję predykatu pred
zwracającą wartość logiczną oraz listę, w której należy szukać. Jeśli zostanie znaleziony element spełniający wymagania predykatu, rekursja kończy się, a funkcja zwraca wartość jako opcję w wyrażeniu Some(head)
. Rekursja kończy się, gdy zostanie dopasowana pusta lista. W tym momencie nie znaleziono wartości head
i zwrócono wartość None
.
Wiele funkcji biblioteki języka F#, które wyszukują kolekcję dla wartości, która może lub nie istnieje, zwraca typ option
. Zgodnie z konwencją te funkcje zaczynają się od prefiksu try
, na przykład Seq.tryFindIndex
.
Opcje mogą być również przydatne, gdy wartość może nie istnieć, na przykład jeśli istnieje możliwość, że podczas próby utworzenia wartości zostanie zgłoszony wyjątek. Poniższy przykład kodu ilustruje to.
open System.IO
let openFile filename =
try
let file = File.Open(filename, FileMode.Create)
Some(file)
with ex ->
eprintf "An exception occurred with message %s" ex.Message
None
Funkcja openFile
w poprzednim przykładzie ma typ string -> File option
, ponieważ zwraca obiekt File
, jeśli plik zostanie otwarty pomyślnie i None
, jeśli wystąpi wyjątek. W zależności od sytuacji może nie być odpowiednim wyborem projektowym, aby przechwycić wyjątek, zamiast pozwalać mu się propagować.
Ponadto nadal można przekazać null
lub wartość null do przypadku Some
opcji. Zwykle należy tego uniknąć i zazwyczaj jest to rutynowe programowanie języka F#, ale jest możliwe ze względu na charakter typów referencyjnych na platformie .NET.
Właściwości i metody opcji
Typ opcji obsługuje następujące właściwości i metody.
Właściwość lub metoda | Typ | Opis |
---|---|---|
None |
'T option |
Statyczny członek tworzący wartość opcji o wartości None . |
IsNone | bool |
Zwraca true , jeśli opcja ma wartość None . |
IsSome | bool |
Zwraca true , jeśli opcja ma wartość, która nie jest None . |
Some |
'T option |
Statyczny element członkowski, który tworzy opcję z wartością inną niż None . |
wartość | 'T |
Zwraca wartość bazową albo zgłasza System.NullReferenceException , jeśli wartość jest None . |
Moduł opcji
Istnieje moduł Option, który zawiera przydatne funkcje, które wykonują operacje na opcjach. Niektóre funkcje powtarzają funkcjonalność właściwości, ale są przydatne w kontekstach, w których potrzebna jest funkcja.
Option.isSome i Option.isNone to funkcje modułu, które testują, czy opcja zawiera wartość.
Option.get pobiera wartość, jeśli istnieje. Jeśli nie ma wartości, zgłasza System.ArgumentException
.
Funkcja Option.bind wykonuje funkcję na wartości, jeśli istnieje wartość. Funkcja musi przyjmować dokładnie jeden argument, a jego typ parametru musi być typem opcji. Zwracana wartość funkcji jest innym typem opcji.
Moduł opcji zawiera również funkcje, które odpowiadają funkcjom dostępnym dla list, tablic, sekwencji i innych typów kolekcji. Te funkcje obejmują Option.map
, Option.iter
, Option.forall
, Option.exists
, Option.foldBack
, Option.fold
i Option.count
. Te funkcje umożliwiają korzystanie z opcji, takich jak zbiór zera lub jednego elementu. Aby uzyskać więcej informacji i przykładów, zobacz omówienie funkcji kolekcji w List.
Konwertowanie na inne typy
Opcje można konwertować na listy lub tablice. Gdy opcja jest konwertowana na jedną z tych struktur danych, wynikowa struktura danych ma zero lub jeden element. Aby przekonwertować opcję na tablicę, użyj Option.toArray
. Aby przekonwertować opcję na listę, użyj Option.toList
.
Konwertowanie opcji z wartościami domyślnymi
Oprócz konwersji na listy i tablice opcje można przekonwertować na inne typy, podając wartości domyślne przy użyciu funkcji Option.defaultValue
. Jest to szczególnie przydatne, gdy chcesz upewnić się, że wartość nie jest None
. Na przykład:
let optionString = Some("F#")
let defaultString = optionString |> Option.defaultValue ""
// defaultString is "F#"
let optionInt = None
let defaultInt = optionInt |> Option.defaultValue 0
// defaultInt is 0
Funkcja Option.defaultValue
umożliwia bezproblemowe obsługę przypadków Some
i None
bez dopasowywania wzorca.