Neues in F# 6
In F# 6 wurden einige Verbesserungen an F# und F# Interactive vorgenommen. Die Version wird mit .NET 6 veröffentlicht.
Sie können das neueste .NET SDK über die .NET-Downloadseite herunterladen.
Erste Schritte
F# 6 ist in allen .NET Core-Distributionen und Visual Studio-Tools verfügbar. Weitere Informationen finden Sie unter Erste Schritte mit F#.
task {…}
F# 6 enthält native Unterstützung für die Erstellung von .NET-Tasks im F#-Code. Sehen Sie sich als Beispiel den folgenden F#-Code an, mit dem ein .NET-kompatibler Task erstellt wird:
let readFilesTask (path1, path2) =
async {
let! bytes1 = File.ReadAllBytesAsync(path1) |> Async.AwaitTask
let! bytes2 = File.ReadAllBytesAsync(path2) |> Async.AwaitTask
return Array.append bytes1 bytes2
} |> Async.StartAsTask
Mit F# 6 kann dieser Code wie folgt umgeschrieben werden.
let readFilesTask (path1, path2) =
task {
let! bytes1 = File.ReadAllBytesAsync(path1)
let! bytes2 = File.ReadAllBytesAsync(path2)
return Array.append bytes1 bytes2
}
Die Taskunterstützung war für F# 5 über die hervorragenden Bibliotheken „TaskBuilder.fs“ und „Ply“ verfügbar. Das Migrieren von Code zur integrierten Unterstützung sollte eine unkomplizierte Angelegenheit sein. Es gibt jedoch einige Unterschiede: Namespaces und Typrückschlüsse unterscheiden sich geringfügig zwischen der integrierten Unterstützung und diesen Bibliotheken, und möglicherweise sind einige zusätzliche Typanmerkungen erforderlich. Bei Bedarf können Sie diese Communitybibliotheken mit F# 6 weiterhin verwenden, wenn Sie explizit darauf verweisen und in jeder Datei die richtigen Namespaces öffnen.
Die Verwendung von task {…}
ähnelt der Verwendung von async {…}
sehr. Die Verwendung von task {…}
bietet mehrere Vorteile gegenüber der Verwendung von async {…}
:
- Der Mehraufwand von
task {...}
ist geringer. Dadurch wird möglicherweise die Leistung in heißen Codepfaden verbessert, in denen die asynchrone Arbeit schnell ausgeführt wird. - Das Debuggen in Einzelschrittausführung sowie Stapelüberwachungen für
task {…}
sind besser. - Die Interoperabilität mit .NET-Paketen, die Tasks erwarten oder erzeugen, ist einfacher.
Wenn Sie mit async {…}
vertraut sind, sollten Sie einige Unterschiede beachten:
task {…}
führt den Task sofort bis zum ersten Wartepunkt aus.task {…}
gibt ein Abbruchtoken nicht implizit weiter.task {…}
führt keine impliziten Abbruchprüfungen durch.task {…}
unterstützt keine asynchronen Endeaufrufe. Das bedeutet, dass die rekursive Verwendung vonreturn! ..
zu Stapelüberläufen führen kann, wenn keine asynchronen Wartevorgänge dazwischen liegen.
Im Allgemeinen sollten Sie in neuem Code task {…}
gegenüber async {…}
bevorzugen, wenn Interoperabilität mit .NET-Bibliotheken erforderlich ist, die Tasks verwenden, und wenn Sie keine asynchronen Codeendeaufrufe und keine implizite Weitergabe von Abbruchtoken nutzen. Im vorhandenen Code sollten Sie erst zu task {…}
wechseln, nachdem Sie Ihren Code überprüft haben, um sicherzustellen, dass Sie die zuvor erwähnten Merkmale von async {…}
nicht benötigen.
Dieses Feature implementiert F# RFC FS-1097.
Einfachere Indizierungssyntax mit expr[idx]
F# 6 erlaubt die Syntax expr[idx]
für die Indizierung und das Slicing von Sammlungen.
Bis einschließlich F# 5 verwendete F# expr.[idx]
als Indizierungssyntax. Das Zulassen der Verwendung von expr[idx]
basiert auf dem wiederholten Feedback von Benutzern, die F# erlernen oder zum ersten Mal sehen, dass eine Indizierung mit Punktnotation als unnötige Abweichung von branchenüblichen Verfahren empfunden wird.
Dies ist kein Breaking Change, da bei Verwendung von expr.[idx]
standardmäßig keine Warnungen ausgegeben werden. Es werden jedoch einige Informationsmeldungen mit Erklärungen zum Code ausgegeben. Sie können optional auch weitere Informationsmeldungen aktivieren. Sie können z. B. eine optionale Informationswarnung (/warnon:3566
) aktivieren, damit Verwendungen der expr.[idx]
-Notation gemeldet werden. Weitere Informationen finden Sie in diesem Artikel zur Indexernotation.
In neuem Code empfehlen wir die systematische Verwendung von expr[idx]
als Indizierungssyntax.
Dieses Feature implementiert F# RFC FS-1110.
Strukturdarstellungen für teilweise aktive Muster
F# 6 erweitert das Feature „aktive Muster“ um optionale Strukturdarstellungen für teilweise aktive Muster. Auf diese Weise können Sie ein Attribut verwenden, um ein teilweise aktives Muster auf die Rückgabe einer Wertoption zu beschränken:
[<return: Struct>]
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| true, int -> ValueSome(int)
| _ -> ValueNone
Die Verwendung des Attributs ist erforderlich. In Nutzungssites ändert sich der Code nicht. Unterm Strich bedeutet das, dass Speicherbelegungen reduziert werden.
Dieses Feature implementiert F# RFC FS-1039.
Überladene benutzerdefinierte Vorgänge in Berechnungsausdrücken
F# 6 ermöglicht die Verwendung von CustomOperationAttribute für die überladenen Methoden.
Sehen Sie sich die folgende Verwendung des Berechnungsausdruck-Generators content
an:
let mem = new System.IO.MemoryStream("Stream"B)
let content = ContentBuilder()
let ceResult =
content {
body "Name"
body (ArraySegment<_>("Email"B, 0, 5))
body "Password"B 2 4
body "BYTES"B
body mem
body "Description" "of" "content"
}
Hier akzeptiert der benutzerdefinierten Vorgang body
eine variierende Anzahl von Argumenten verschiedener Typen. Dies wird durch die Implementierung des folgenden Generators unterstützt, der Überladungen verwendet:
type Content = ArraySegment<byte> list
type ContentBuilder() =
member _.Run(c: Content) =
let crlf = "\r\n"B
[|for part in List.rev c do
yield! part.Array[part.Offset..(part.Count+part.Offset-1)]
yield! crlf |]
member _.Yield(_) = []
[<CustomOperation("body")>]
member _.Body(c: Content, segment: ArraySegment<byte>) =
segment::c
[<CustomOperation("body")>]
member _.Body(c: Content, bytes: byte[]) =
ArraySegment<byte>(bytes, 0, bytes.Length)::c
[<CustomOperation("body")>]
member _.Body(c: Content, bytes: byte[], offset, count) =
ArraySegment<byte>(bytes, offset, count)::c
[<CustomOperation("body")>]
member _.Body(c: Content, content: System.IO.Stream) =
let mem = new System.IO.MemoryStream()
content.CopyTo(mem)
let bytes = mem.ToArray()
ArraySegment<byte>(bytes, 0, bytes.Length)::c
[<CustomOperation("body")>]
member _.Body(c: Content, [<ParamArray>] contents: string[]) =
List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c
Dieses Feature implementiert F# RFC FS-1056.
„as“-Muster
In F# 6 kann die rechte Seite eines as
-Musters jetzt selbst ein Muster sein. Das ist wichtig, wenn ein Typtest einer Eingabe einen stärkeren Typ zugewiesen hat. Beachten Sie z. B. folgenden Code:
type Pair = Pair of int * int
let analyzeObject (input: obj) =
match input with
| :? (int * int) as (x, y) -> printfn $"A tuple: {x}, {y}"
| :? Pair as Pair (x, y) -> printfn $"A DU: {x}, {y}"
| _ -> printfn "Nope"
let input = box (1, 2)
Bei jedem Muster wird das Eingabeobjekt typgeprüft. Die rechte Seite des as
-Musters darf jetzt wiederum ein Muster sein, das selbst mit dem Objekt des stärkeren Typs übereinstimmen kann.
Dieses Feature implementiert F# RFC FS-1105.
Überarbeitungen der Einzugssyntax
In F# 6 wurden einige Inkonsistenzen und Einschränkungen bei der Verwendung einer Syntax mit Einzügen entfernt. Siehe RFC FS-1108. Damit werden zehn wesentliche Probleme behoben, die von F#-Benutzern seit F# 4.0 gemeldet werden.
In F# 5 war beispielsweise der folgende Code zulässig:
let c = (
printfn "aaaa"
printfn "bbbb"
)
Der folgende Code war jedoch nicht zulässig (es wurde eine Warnung erzeugt):
let c = [
1
2
]
In F# 6 sind beide zulässig. Damit lässt sich F# einfacher erlernen und verwenden. Hadrian Tang, Mitglied der F#-Community, war hierbei federführend und hat das Feature höchst wertvollen systematischen Tests unterzogen.
Dieses Feature implementiert F# RFC FS-1108.
Weitere implizite Konvertierungen
In F# 6 wurde die Unterstützung für zusätzliche „implizite“ und „typgesteuerte“ Konvertierungen aktiviert, wie in RFC FS-1093 beschrieben.
Diese Änderung bringt drei Vorteile mit sich:
- Es sind weniger explizite Upcasts erforderlich.
- Es sind weniger explizite Integerkonvertierungen erforderlich.
- Es wurde erstklassige Unterstützung für implizite Konvertierungen im .NET-Stil hinzugefügt.
Dieses Feature implementiert F# RFC FS-1093.
Zusätzliche implizite Upcastkonvertierungen
F# 6 implementiert zusätzliche implizite Upcastkonvertierungen. In F# 5 und früheren Versionen wurden beispielsweise Upcasts für den Rückgabeausdruck benötigt, wenn eine Funktion implementiert wurde, bei der die Ausdrücke unterschiedliche Untertypen in verschiedenen Verzweigungen aufwiesen, auch wenn eine Typanmerkung vorhanden war. Sehen Sie sich den folgenden F# 5-Code an:
open System
open System.IO
let findInputSource () : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt") :> TextReader
Hier berechnen die Verzweigungen der Bedingung einen TextReader
bzw. einen StreamReader
, und der Upcast wird hinzugefügt, damit beide Verzweigungen den Typ „StreamReader“ aufweisen. In F# 6 werden diese Upcasts jetzt automatisch hinzugefügt. Damit wird der Code einfacher:
let findInputSource () : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt")
Optional können Sie die Warnung /warnon:3388
aktivieren, um an jedem Punkt, an dem ein zusätzlicher impliziter Upcast verwendet wird, eine Warnung anzuzeigen, wie in Optionale Warnungen für implizite Konvertierungen beschrieben.
Implizite Integerkonvertierungen
In F# 6 werden 32-Bit-Integer-Werte auf 64-Bit-Integer-Werte erweitert, wenn beide Typen bekannt sind. Sehen Sie sich beispielsweise eine typische API-Form an:
type Tensor(…) =
static member Create(sizes: seq<int64>) = Tensor(…)
In F# 5 müssen Integerliterale für int64 verwendet werden:
Tensor.Create([100L; 10L; 10L])
oder
Tensor.Create([int64 100; int64 10; int64 10])
In F# 6 erfolgt die Erweiterung automatisch von int32
auf int64
, von int32
auf nativeint
und von int32
auf double
, wenn während des Typrückschlusses sowohl Quell- als auch Zieltyp bekannt sind. In Fällen wie den obigen Beispielen können also int32
-Literale verwendet werden:
Tensor.Create([100; 10; 10])
Trotz dieser Änderung verwendet F# in den meisten Fällen weiterhin eine explizite Erweiterung numerischer Typen. Die implizite Erweiterung gilt beispielsweise nicht für andere numerische Typen wie int8
oder int16
oder zur Erweiterung von float32
auf float64
. Sie gilt auch dann nicht, wenn entweder der Quell- oder der Zieltyp unbekannt ist. Sie können optional auch die Warnung /warnon:3389
aktivieren, um an jedem Punkt, an dem eine zusätzliche implizite numerische Erweiterung verwendet wird, eine Warnung anzuzeigen, wie in Optionale Warnungen für implizite Konvertierungen beschrieben.
Erstklassige Unterstützung für implizite Konvertierungen im .NET-Stil
In F# 6 werden „op_Implicit“-Konvertierungen von .NET beim Aufrufen von Methoden automatisch im F#-Code angewendet. In F# 5 war bei der Arbeit mit .NET-APIs für XML beispielsweise die Verwendung von XName.op_Implicit
erforderlich:
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")
In F# 6 werden op_Implicit
-Konvertierungen automatisch auf Argumentausdrücke angewendet, wenn die Typen für Quellausdruck und Zieltyp verfügbar sind:
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")
Optional können Sie die Warnung /warnon:3395
aktivieren, um an jedem Punkt, an dem eine Erweiterung von op_Implicit
-Konvertierungen in Methodenargumenten verwendet wird, eine Warnung anzuzeigen, wie in Optionale Warnungen für implizite Konvertierungen beschrieben.
Hinweis
In der ersten Version von F# 6 lautete diese Warnnummer /warnon:3390
. Aufgrund eines Konflikts wurde die Warnnummer später zu /warnon:3395
aktualisiert.
Optionale Warnungen für implizite Konvertierungen
Typgesteuerte und implizite Konvertierungen interagieren zuweilen nur unzureichend mit Typrückschlüssen, was zu schwer verständlichem Code führen kann. Aus diesem Grund gibt es einige Entschärfungen, um sicherzustellen, dass dieses Feature im F#-Code nicht missbraucht wird. Zunächst muss sowohl der Quell- als auch der Zieltyp eindeutig bekannt sein, ohne jede Mehrdeutigkeit oder weitere Typrückschlüsse. Zweitens können Opt-In-Warnungen eingerichtet werden, die jede Verwendung impliziter Konvertierungen melden, wobei eine Warnung standardmäßig aktiviert ist:
/warnon:3388
(zusätzlicher impliziter Upcast)/warnon:3389
(implizite numerische Erweiterung)/warnon:3391
(„op_Implicit“ bei Nicht-Methoden-Argumenten, standardmäßig aktiviert)/warnon:3395
(„op_Implicit“ bei Methodenargumenten)
Wenn Ihr Team jegliche Verwendung impliziter Konvertierungen untersagen möchte, können Sie auch /warnaserror:3388
, /warnaserror:3389
, /warnaserror:3391
und /warnaserror:3395
angeben.
Formatierung für Binärzahlen
F# 6 fügt den verfügbaren Formatbezeichnern das %B
-Muster für binäre Zahlenformate hinzu. Sehen Sie sich den folgenden F#-Code an:
printf "%o" 123
printf "%B" 123
Dieser Code führt zu folgender Ausgabe:
173
1111011
Dieses Feature implementiert F# RFC FS-1100.
Verwerfen bei use-Bindungen
F# 6 lässt die Verwendung von _
in einer use
-Bindung zu, z. B.:
let doSomething () =
use _ = System.IO.File.OpenText("input.txt")
printfn "reading the file"
Dieses Feature implementiert F# RFC FS-1102.
InlineIfLambda
Der F#-Compiler enthält einen Optimierer, der ein Inlining des Codes ausführt. In F# 6 haben wir ein neues deklaratives Feature hinzugefügt, mit dem der Code optional angeben kann, dass, wenn ein Argument als Lambdafunktion festgelegt wird, dieses Argument in Aufrufsites immer inline sein soll.
Betrachten Sie beispielsweise die folgende iterateTwice
-Funktion zum Durchlaufen eines Arrays:
let inline iterateTwice ([<InlineIfLambda>] action) (array: 'T[]) =
for j = 0 to array.Length-1 do
action array[j]
for j = 0 to array.Length-1 do
action array[j]
Wenn die Aufrufseite folgendermaßen lautet:
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
Dann sieht der Code nach Inlining und anderen Optimierungen so aus:
let arr = [| 1.. 100 |]
let mutable sum = 0
for j = 0 to arr.Length-1 do
sum <- sum + arr[j]
for j = 0 to arr.Length-1 do
sum <- sum + arr[j]
Im Gegensatz zu früheren Versionen von F# wird diese Optimierung unabhängig von der Größe des beteiligten Lambdaausdrucks angewendet. Dieses Feature kann auch verwendet werden, um die Auflösung von Schleifen und ähnliche Transformationen zuverlässiger zu implementieren.
Eine Opt-In-Warnung (/warnon:3517
, standardmäßig deaktiviert) kann aktiviert werden, um Stellen in Ihrem Code anzugeben, an denen InlineIfLambda
-Argumente nicht an Lambdaausdrücke in Aufrufsites gebunden sind. In normalen Situationen sollte diese Warnung nicht aktiviert werden. Bei bestimmten Arten der Hochleistungsprogrammierung kann sie jedoch hilfreich sein, sicherzustellen, dass der gesamte Code inline und vereinfacht ist.
Dieses Feature implementiert F# RFC FS-1098.
Fortsetzbarer Code
Die task {…}
-Unterstützung von F# 6 basiert auf fortsetzbarem Code (resumable code) (RFC FS-1087). Fortsetzbarer Code ist ein technisches Feature, mit dem viele Arten von hochleistungsfähigen Zustandsautomaten („async“ und „yield“) erstellt werden können.
Weitere Sammlungsfunktionen
FSharp.Core 6.0.0 fügt den grundlegenden Sammlungsfunktionen fünf neue Vorgänge hinzu. Dabei handelt es sich um diese Funktionen:
- List/Array/Seq.insertAt
- List/Array/Seq.removeAt
- List/Array/Seq.updateAt
- List/Array/Seq.insertManyAt
- List/Array/Seq.removeManyAt
Diese Funktionen führen alle Kopier- und Aktualisierungsvorgänge für den entsprechenden Sammlungstyp oder die entsprechende Sammlungssequenz aus. Dieser Vorgangstyp ist eine Art „Funktionsaktualisierung“. Beispiele für die Verwendung dieser Funktionen finden Sie in der entsprechenden Dokumentation, z. B. List.insertAt.
Betrachten Sie beispielsweise die Modell-, Nachrichten- und Aktualisierungslogik für eine einfache „Todo List“-Anwendung, die im Elmish-Stil geschrieben wurde. Hier interagiert der Benutzer mit der Anwendung und generiert dabei Nachrichten. Die update
-Funktion verarbeitet diese Nachrichten und erzeugt ein neues Modell:
type Model =
{ ToDo: string list }
type Message =
| InsertToDo of index: int * what: string
| RemoveToDo of index: int
| LoadedToDos of index: int * what: string list
let update (model: Model) (message: Message) =
match message with
| InsertToDo (index, what) ->
{ model with ToDo = model.ToDo |> List.insertAt index what }
| RemoveToDo index ->
{ model with ToDo = model.ToDo |> List.removeAt index }
| LoadedToDos (index, what) ->
{ model with ToDo = model.ToDo |> List.insertManyAt index what }
Mit diesen neuen Funktionen ist die Logik klar und einfach und basiert nur auf unveränderlichen Daten.
Dieses Feature implementiert F# RFC FS-1113.
„Map“ unterstützt „Keys“ und „Values“
In FSharp.Core 6.0.0 unterstützt der Map
-Typ jetzt die Eigenschaften Keys und Values. Diese Eigenschaften kopieren die zugrunde liegende Sammlung nicht.
Dieses Feature ist in F# RFC FS-1113 dokumentiert.
Zusätzliche intrinsische Funktionen für NativePtr
FSharp.Core 6.0.0 fügt dem NativePtr-Modul neue intrinsische Funktionen hinzu:
NativePtr.nullPtr
NativePtr.isNullPtr
NativePtr.initBlock
NativePtr.clear
NativePtr.copy
NativePtr.copyBlock
NativePtr.ofILSigPtr
NativePtr.toILSigPtr
Wie anderen Funktionen in NativePtr
auch sind diese Funktionen inline, und ihre Verwendung gibt Warnungen aus, sofern nicht /nowarn:9
verwendet wird. Die Verwendung dieser Funktionen ist auf nicht verwaltete Typen beschränkt.
Dieses Feature ist in F# RFC FS-1109 dokumentiert.
Zusätzliche numerische Typen mit Anmerkungen zu Einheiten
In F# 6 unterstützen die folgenden Typen oder Typkürzelaliase jetzt Anmerkungen zu Maßeinheiten. Die neuen Ergänzungen werden fett formatiert angezeigt:
F#-Alias | CLR-Typ |
---|---|
float32 /single |
System.Single |
float /double |
System.Double |
decimal |
System.Decimal |
sbyte /int8 |
System.SByte |
int16 |
System.Int16 |
int /int32 |
System.Int32 |
int64 |
System.Int64 |
byte /uint8 |
System.Byte |
uint16 |
System.UInt16 |
uint /uint32 |
System.UInt32 |
uint64 |
System.UIn64 |
nativeint |
System.IntPtr |
unativeint |
System.UIntPtr |
Sie können z. B. eine ganze Zahl ohne Vorzeichen wie folgt mit einer Anmerkung versehen:
[<Measure>]
type days
let better_age = 3u<days>
Dieses Feature ist in F# RFC FS-1091 dokumentiert.
Informationswarnungen für selten verwendete Symboloperatoren
F# 6 fügt Empfehlungen hinzu, um die Verwendung von :=
, !
, incr
und decr
in F# 6 und darüber hinaus nach und nach zu entfernen. Die Verwendung dieser Operatoren und Funktionen erzeugt Informationsmeldungen, in denen Sie aufgefordert werden, Ihren Code durch die explizite Verwendung der Value
-Eigenschaft zu ersetzen.
In der F#-Programmierung können Verweiszellen für dem Heap zugeordnete änderbare Register verwendet werden. Diese sind zwar gelegentlich nützlich, aber in der modernen F#-Programmierung nur selten erforderlich, da stattdessen let mutable
verwendet werden kann. Die F#-Kernbibliothek enthält die beiden Operatoren :=
und !
sowie die beiden Funktionen incr
und decr
speziell im Zusammenhang mit Verweiszellen. Aufgrund dieser Operatoren sind Verweiszellen in der F#-Programmierung von zentralerer Bedeutung, als sie sein müssten. Daher müssen alle F#-Programmierer diese Operatoren kennen. Darüber hinaus kann der !
-Operator leicht mit dem not
-Vorgang in C# und anderen Sprachen verwechselt werden – eine Quelle für Fehler, die beim Übersetzen von Code nur schwer erkennbar sein können.
Ziel dieser Änderung ist es, die Anzahl der Operatoren zu reduzieren, die F#-Programmierer kennen müssen, und somit F# für Einsteiger zu vereinfachen.
Sehen Sie sich als Beispiel den folgenden F# 5-Code an:
let r = ref 0
let doSomething() =
printfn "doing something"
r := !r + 1
Zunächst werden Verweiszellen in der modernen F#-Programmierung selten benötigt, da normalerweise let mutable
verwendet werden kann:
let mutable r = 0
let doSomething() =
printfn "doing something"
r <- r + 1
Wenn Sie Verweiszellen verwenden, gibt F# 6 eine Informationswarnung aus, in der Sie aufgefordert werden, die letzte Zeile zu r.Value <- r.Value + 1
zu ändern. Außerdem wird ein Link zu weiteren Informationen zur geeigneten Verwendung von Verweiszellen angezeigt.
let r = ref 0
let doSomething() =
printfn "doing something"
r.Value <- r.Value + 1
Diese Meldungen sind keine Warnungen, sondern Informationsmeldungen, die in der IDE- und Compilerausgabe angezeigt werden. F# ist weiterhin abwärtskompatibel.
Dieses Feature implementiert F# RFC FS-1111.
F#-Tools: .NET 6 als Standard für die Skripterstellung in Visual Studio
Wenn Sie ein F#-Skript (.fsx
) in Visual Studio öffnen oder ausführen, wird es standardmäßig unter Verwendung von .NET 6 mit 64-Bit-Ausführung analysiert und ausgeführt. Diese Funktionalität befand sich in den späteren Versionen von Visual Studio 2019 in der Vorschau und ist jetzt standardmäßig aktiviert.
Zum Aktivieren der .NET Framework-Skripterstellung wählen Sie Tools>Optionen>F#-Tools>F# Interactive aus. Legen Sie .NET Core-Skripterstellung auf false fest, und starten Sie das F# Interactive-Fenster neu. Diese Einstellung wirkt sich sowohl auf die Bearbeitung als auch auf die Ausführung von Skripts aus. Um die 32-Bit-Ausführung für die .NET Framework-Skripterstellung zu aktivieren, legen Sie auch 64-Bit F# Interactive auf false fest. Es gibt keine 32-Bit-Option für die .NET Core-Skripterstellung.
F#-Tools: Anheften der SDK-Version Ihrer F#-Skripts
Wenn Sie ein Skript mit dotnet fsi
in einem Verzeichnis ausführen, das eine global.json-Datei mit einer .NET SDK-Einstellung enthält, wird die aufgelistete Version des .NET SDK verwendet, um das Skript auszuführen und zu bearbeiten. Dieses Feature war in den späteren Versionen von F# 5 verfügbar.
Ein Beispiel: Es gibt ein Skript in einem Verzeichnis mit der folgenden global.json-Datei, das eine .NET SDK-Versionsrichtlinie angibt:
{
"sdk": {
"version": "5.0.200",
"rollForward": "minor"
}
}
Wenn Sie das Skript mit dotnet fsi
in diesem Verzeichnis ausführen, wird die SDK-Version berücksichtigt. Dies ist ein leistungsstarkes Feature, mit dem Sie das SDK, das zum Kompilieren, Analysieren und Ausführen Ihrer Skripts verwendet wird, „sperren“ können.
Wenn Sie Ihr Skript in Visual Studio und anderen IDEs öffnen und bearbeiten, berücksichtigen die Tools diese Einstellung beim Analysieren und Überprüfen Ihres Skripts. Wenn das SDK nicht gefunden wird, müssen Sie es auf Ihrem Entwicklungscomputer installieren.
Unter Linux und anderen Unix-Systemen können Sie dies mit einem Shebang kombinieren, um auch eine Sprachversion für die direkte Ausführung des Skripts anzugeben. Ein einfacher Shebang für script.fsx
ist:
#!/usr/bin/env -S dotnet fsi
printfn "Hello, world"
Jetzt kann das Skript direkt mit script.fsx
ausgeführt werden. Sie können dies mit einer bestimmten, nicht standardmäßigen Sprachversion wie folgt kombinieren:
#!/usr/bin/env -S dotnet fsi --langversion:5.0
Hinweis
Diese Einstellung wird von Bearbeitungstools ignoriert, die das Skript unter Annahme der neuesten Sprachversion analysieren.
Entfernen von Legacyfeatures
Bereits seit F# 2.0 geben einige als veraltet markierte Legacyfeatures Warnungen aus. Bei Verwendung dieser Features in F# 6 werden Fehler ausgegeben, wenn Sie nicht explizit /langversion:5.0
verwenden. Folgende Features geben Fehler aus:
- Mehrere generische Parameter mit einem Postfixtypnamen, z. B.
(int, int) Dictionary
. Dies wird in F# 6 zu einem Fehler. Stattdessen sollte die StandardsyntaxDictionary<int,int>
verwendet werden. #indent "off"
. Dies wird zu einem Fehler.x.(expr)
. Dies wird zu einem Fehler.module M = struct … end
. Dies wird zu einem Fehler.- Verwenden der Eingaben
*.ml
und*.mli
. Dies wird zu einem Fehler. - Verwenden von
(*IF-CAML*)
oder(*IF-OCAML*)
. Dies wird zu einem Fehler. - Verwenden von
land
,lor
,lxor
,lsl
,lsr
oderasr
als Infixoperatoren. Dies sind Infixschlüsselwörter in F#, da sie in OCaml Infixschlüsselwörter waren und in FSharp.Core nicht definiert sind. Bei Verwendung dieser wird jetzt eine Warnung ausgegeben.
Dies implementiert F# RFC FS-1114.