Suche…
Definition der Option
Eine Option
ist eine diskriminierte Gewerkschaft mit zwei Fällen: None
oder Some
.
type Option<'T> = Some of 'T | None
Verwenden Sie die Option <'T> über Nullwerte
In funktionalen Programmiersprachen wie F#
null
als potenziell schädlich und als schlecht (nicht idiomatisch) angesehen.
Betrachten Sie diesen C#
-Code:
string x = SomeFunction ();
int l = x.Length;
x.Length
wird geworfen, wenn x
null
, fügen Sie den Schutz hinzu:
string x = SomeFunction ();
int l = x != null ? x.Length : 0;
Oder:
string x = SomeFunction () ?? "";
int l = x.Length;
Oder:
string x = SomeFunction ();
int l = x?.Length;
In idiomatic werden keine F#
null
verwendet, daher sieht unser Code folgendermaßen aus:
let x = SomeFunction ()
let l = x.Length
Manchmal müssen jedoch leere oder ungültige Werte dargestellt werden. Dann können wir Option<'T>
:
let SomeFunction () : string option = ...
SomeFunction
entweder Some
string
oder None
. Wir extrahieren den string
Wert mithilfe von Pattern-Matching
let v =
match SomeFunction () with
| Some x -> x.Length
| None -> 0
Der Grund, warum dieser Code weniger anfällig ist als:
string x = SomeFunction ();
int l = x.Length;
Ist, weil wir Length
mit einer string option
aufrufen können. Wir müssen den string
Wert mithilfe von Pattern-Matching extrahieren. Dadurch wird sichergestellt, dass der string
Wert sicher verwendet werden kann.
Das Optionsmodul ermöglicht die eisenbahnorientierte Programmierung
Fehlerbehandlung ist wichtig, kann jedoch einen eleganten Algorithmus zum Durcheinander bringen. Eisenbahnorientierte Programmierung ( ROP
) wird verwendet, um die Fehlerbehandlung elegant und komponierbar zu gestalten.
Betrachten Sie die einfache Funktion f
:
let tryParse s =
let b, v = System.Int32.TryParse s
if b then Some v else None
let f (g : string option) : float option =
match g with
| None -> None
| Some s ->
match tryParse s with // Parses string to int
| None -> None
| Some v when v < 0 -> None // Checks that int is greater than 0
| Some v -> v |> float |> Some // Maps int to float
Der Zweck von f
ist die Eingabe zu analysieren string
- Wert (wenn es Some
) in einen int
. Wenn das int
größer als 0
, werfen wir es in einen float
. In allen anderen Fällen retten wir mit None
.
Eine extrem einfache Funktion, die verschachtelte match
verringert jedoch die Lesbarkeit erheblich.
ROP
stellt fest, dass wir zwei Arten von Ausführungspfaden in unserem Programm haben
- Glücklicher Weg - Will irgendwann
Some
Wert berechnen - Fehlerpfad - Alle anderen Pfade erzeugen
None
Da die Fehlerpfade häufiger sind, neigen sie dazu, den Code zu übernehmen. Wir möchten, dass der Happy-Path-Code der sichtbarste Codepfad ist.
Eine äquivalente Funktion g
die ROP
könnte folgendermaßen aussehen:
let g (v : string option) : float option =
v
|> Option.bind tryParse // Parses string to int
|> Option.filter ((<) 0) // Checks that int is greater than 0
|> Option.map float // Maps int to float
Es sieht sehr danach aus, wie wir Listen und Sequenzen in F#
.
Man kann eine Option<'T>
wie eine List<'T>
, die nur 0
oder 1
Elemente enthalten kann, wobei Option.bind
sich wie List.pick
verhält (konzeptionell ist Option.bind
besser auf List.collect
List.pick
möglicherweise jedoch List.pick
leichter zu verstehen).
bind
, filter
und map
behandelt die Fehlerpfade und g
enthält nur den Code für den glücklichen Pfad.
Alle Funktionen, die Option<_>
direkt akzeptieren und Option<_>
direkt mit |>
und >>
.
ROP
erhöht daher die Lesbarkeit und Komposierbarkeit.
Verwendung von Optionstypen aus C #
Es ist keine gute Idee, Optionstypen mit C # -Code zu versehen, da C # keine Möglichkeit hat, sie zu behandeln. Sie haben die Möglichkeit, entweder FSharp.Core
als Abhängigkeit in Ihrem C # -Projekt einzuführen (was Sie tun müssten, wenn Sie eine F # -Bibliothek verwenden, die nicht für die Interop mit C # vorgesehen ist) oder die Werte von None
in null
ändern.
Pre-F # 4.0
Dazu erstellen Sie eine eigene Konvertierungsfunktion:
let OptionToObject opt =
match opt with
| Some x -> x
| None -> null
Für System.Nullable
Sie auf Boxen oder System.Nullable
.
let OptionToNullable x =
match x with
| Some i -> System.Nullable i
| None -> System.Nullable ()
F # 4.0
In F # 4.0 wurden die Funktionen ofObj
, toObj
, ofNullable
und toNullable
in das Option
. In F # interactive können sie wie folgt verwendet werden:
let l1 = [ Some 1 ; None ; Some 2]
let l2 = l1 |> List.map Option.toNullable;;
// val l1 : int option list = [Some 1; null; Some 2]
// val l2 : System.Nullable<int> list = [1; null; 2]
let l3 = l2 |> List.map Option.ofNullable;;
// val l3 : int option list = [Some 1; null; Some 2]
// Equality
l1 = l2 // fails to compile: different types
l1 = l3 // true
Beachten Sie, dass None
intern zu null
kompiliert wird. Für F # ist dies jedoch None
.
let lA = [Some "a"; None; Some "b"]
let lB = lA |> List.map Option.toObj
// val lA : string option list = [Some "a"; null; Some "b"]
// val lB : string list = ["a"; null; "b"]
let lC = lB |> List.map Option.ofObj
// val lC : string option list = [Some "a"; null; Some "b"]
// Equality
lA = lB // fails to compile: different types
lA = lC // true