F#
Der Typ "Einheit"
Suche…
Was nützt ein 0-Tupel?
Ein 2-Tupel oder ein 3-Tupel repräsentiert eine Gruppe verwandter Elemente. (Punkte im 2D-Raum, RGB-Werte einer Farbe usw.) Ein 1-Tupel ist nicht sehr nützlich, da es leicht durch ein einzelnes int
.
Ein 0-Tupel erscheint noch nutzloser, da es absolut nichts enthält. Es hat jedoch Eigenschaften, die es in funktionalen Sprachen wie F # sehr nützlich machen. Zum Beispiel hat der 0-Tupel-Typ genau einen Wert, normalerweise als ()
. Alle 0-Tupel haben diesen Wert, es handelt sich also im Wesentlichen um einen Singleton-Typ. In den meisten funktionalen Programmiersprachen, einschließlich F #, wird dies die gerufene unit
Typ.
Funktionen, die void
in C # zurückgeben, geben den unit
in F # zurück:
let printResult = printfn "Hello"
Führen Sie das im interaktiven F # -Interpreter aus, und Sie werden sehen:
val printResult : unit = ()
Dies bedeutet, dass der Wert printResult
vom Typ unit
ist und den Wert ()
(das leere Tupel, der einzige Wert des unit
).
Funktionen können den unit
als Parameter verwenden. In F # sehen Funktionen möglicherweise so aus, als würden sie keine Parameter übernehmen. Tatsächlich nehmen sie jedoch einen einzigen Parameter der unit
. Diese Funktion:
let doMath() = 2 + 4
ist eigentlich gleichbedeutend mit:
let doMath () = 2 + 4
Das heißt, eine Funktion, die einen Parameter der unit
und den int
Wert 6 zurückgibt. Wenn Sie sich die int
ansehen, die der interaktive F # -Interpreter bei der Definition dieser Funktion druckt, wird Folgendes angezeigt:
val doMath : unit -> int
Die Tatsache, dass alle Funktionen mindestens einen Parameter annehmen und einen Wert zurückgeben, auch wenn dieser Wert manchmal ein "nutzloser" Wert wie ()
, bedeutet, dass die Funktionskomposition in F # viel einfacher ist als in Sprachen, die das nicht haben unit
- Typ. Aber das ist ein fortgeschritteneres Thema, auf das wir später noch eingehen werden. Denken Sie im Moment daran, dass, wenn Sie unit
in einer Funktionssignatur oder ()
in den Parametern einer Funktion sehen, dies der 0-Tupel-Typ ist, der dazu dient, zu sagen: "Diese Funktion nimmt oder gibt keine sinnvollen Werte zurück."
Verschiebung der Ausführung von Code
Wir können den unit
Typ als Funktionsargument verwenden, um Funktionen zu definieren, die erst später ausgeführt werden sollen. Dies ist häufig bei asynchronen Hintergrundaufgaben nützlich, wenn der Haupt-Thread möglicherweise vordefinierte Funktionen des Hintergrund-Threads auslöst, z. B. das Verschieben in eine neue Datei oder wenn eine Let-Bindung nicht sofort ausgeführt werden soll:
module Time =
let now = System.DateTime.Now // value is set and fixed for duration of program
let now() = System.DateTime.Now // value is calculated when function is called (each time)
Im folgenden Code definieren wir Code zum Starten eines "Arbeiters", der einfach alle 2 Sekunden den Wert ausgibt, an dem er arbeitet. Der Arbeiter gibt dann zwei Funktionen zurück, mit denen er gesteuert werden kann - eine, mit der er zum nächsten Wert bewegt werden kann, und eine, die die Arbeit unterbindet. Dies müssen Funktionen sein, da wir nicht möchten, dass ihre Körper ausgeführt werden, bis wir dies wünschen. Andernfalls würde der Arbeiter sofort zum zweiten Wert wechseln und herunterfahren, ohne etwas getan zu haben.
let startWorker value =
let current = ref value
let stop = ref false
let nextValue () = current := !current + 1
let stopOnNextTick () = stop := true
let rec loop () = async {
if !stop then
printfn "Stopping work."
return ()
else
printfn "Working on %d." !current
do! Async.Sleep 2000
return! loop () }
Async.Start (loop ())
nextValue, stopOnNextTick
Wir können dann einen Arbeiter damit anfangen
let nextValue, stopOnNextTick = startWorker 12
und die Arbeit beginnt - wenn wir in F # interaktiv sind, werden die Meldungen alle zwei Sekunden in der Konsole ausgedruckt. Wir können dann rennen
nextValue ()
Die Meldungen zeigen an, dass der Wert, an dem gearbeitet wird, zum nächsten verschoben wurde.
Wenn es Zeit ist, die Arbeit zu beenden, können wir das ausführen
stopOnNextTick ()
Funktion, die die Abschlussnachricht druckt, und beendet sich dann.
Der unit
ist hier wichtig, um "keine Eingabe" zu bedeuten - die Funktionen enthalten bereits alle Informationen, die sie zum Arbeiten benötigen, und der Anrufer darf dies nicht ändern.