Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
F# 6 fügt der F#-Sprache und F# Interactive mehrere Verbesserungen hinzu. Sie wird mit .NET 6 veröffentlicht.
Sie können das neueste .NET SDK von der .NET-Downloadseite herunterladen.
Get started
F# 6 ist in allen .NET Core-Verteilungen und Visual Studio-Tools verfügbar. Weitere Informationen finden Sie unter "Erste Schritte mit F#".
Aufgabe {...}
F# 6 enthält systemeigene Unterstützung für das Erstellen von .NET-Aufgaben in F#-Code mithilfe von Aufgabenausdrücken. Aufgabenausdrücke ähneln asynchronen Ausdrücken, ermöglichen es Ihnen jedoch, .NET-Aufgaben direkt zu erstellen.
Betrachten Sie z. B. den folgenden F#-Code, um eine .NET-kompatible Aufgabe zu erstellen.
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 Aufgabenunterstützung war für F# 5 über die hervorragenden TaskBuilder.fs- und Ply-Bibliotheken verfügbar. Es sollte einfach sein, Code zur integrierten Unterstützung zu migrieren. Es gibt jedoch einige Unterschiede: Namespaces und Typableitung unterscheiden sich geringfügig zwischen der integrierten Unterstützung und diesen Bibliotheken, und es können einige zusätzliche Typanmerkungen erforderlich sein. Bei Bedarf können Sie diese Communitybibliotheken weiterhin mit F# 6 verwenden, wenn Sie explizit darauf verweisen und die richtigen Namespaces in jeder Datei öffnen.
Die Verwendung task {…} ist mit der Verwendung async {…}sehr ähnlich. Die Verwendung task {…} hat mehrere Vorteile gegenüber async {…}:
- Der Mehraufwand
task {...}ist geringer, was möglicherweise die Leistung in kritischen Codeabschnitten verbessert, in denen die asynchrone Arbeit schnell ausgeführt wird. - Das Debuggen, einschließlich der schrittweisen Ausführung und der Stack-Traces, ist bei
task {…}besser. - Die Interoperabilität mit .NET-Paketen, die Aufgaben erwarten oder erzeugen, ist einfacher.
Wenn Sie mit async {…} vertraut sind, gibt es einige Unterschiede, die Sie beachten sollten.
-
task {…}führt die Aufgabe sofort bis zum ersten "await"-Punkt aus. -
task {…}gibt kein Abbruchtoken implizit weiter. -
task {…}führt keine impliziten Stornierungsprüfungen durch. -
task {…}unterstützt keine asynchronen Tailcalls. Dies bedeutet, dass die Verwendungreturn! ..rekursiv zu Stapelüberläufen führen kann, wenn keine asynchronen Wartezeiten vorhanden sind.
Im Allgemeinen sollten Sie die Verwendung von task {…} über async {…} in neuem Code in Betracht ziehen, wenn Sie mit .NET-Bibliotheken zusammenarbeiten, die Tasks verwenden, und wenn Sie nicht auf asynchrone Code-Tailcalls oder implizite Abbruchtokenweitergabe angewiesen sind. Im vorhandenen Code sollten Sie nur zu task {…} wechseln, nachdem Sie Ihren Code überprüft haben, um sicherzustellen, dass Sie sich nicht auf die zuvor erwähnten Merkmale verlassen async {…}.
Dieses Feature implementiert F# RFC FS-1097.
Einfachere Indizierungssyntax mit expr[idx]
F# 6 ermöglicht die Syntax expr[idx] für Indizieren und Slicing von Auflistungen.
Bis einschließlich F# 5 hat F# die expr.[idx] Indizierungssyntax verwendet. Das Zulassen der Nutzung von expr[idx] basiert auf wiederholtem Feedback von Lernenden von F# oder wenn sie F# zum ersten Mal sehen, dass die Verwendung der Punktnotationsindizierung als unnötige Abweichung von der üblichen Branchenpraxis wahrgenommen wird.
Dies ist keine Breaking Change, da standardmäßig keine Warnungen bei der Verwendung von expr.[idx] ausgegeben werden. Einige Informationsmeldungen, die Codeklärungen vorschlagen, werden jedoch ausgegeben. Sie können optional auch weitere Informationsmeldungen aktivieren. Sie können z. B. eine optionale Informationswarnung (/warnon:3366) aktivieren, um die Verwendung der expr.[idx] Notation zu melden. Weitere Informationen finden Sie unter Indexer Notation.
Im neuen Code empfehlen wir die systematische Verwendung expr[idx] als Indizierungssyntax.
Dieses Feature implementiert F# RFC FS-1110.
Strukturdarstellungen für partielle aktive Muster
F# 6 erweitert das Feature "aktive Muster" mit optionalen Strukturdarstellungen für partielle aktive Muster. Auf diese Weise können Sie ein Attribut verwenden, um ein partielles aktives Muster einzuschränken, um eine Wertoption zurückzugeben:
[<return: Struct>]
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| true, int -> ValueSome(int)
| _ -> ValueNone
Die Verwendung des Attributs ist erforderlich. Bei Verwendungsorten ändert sich der Code nicht. Das Nettoergebnis besteht darin, dass die Zuteilungen reduziert werden.
Dieses Feature implementiert F# RFC FS-1039.
Überladene benutzerdefinierte Vorgänge in Berechnungsausdrücken
Mit F# 6 können Sie CustomOperationAttribute für die überladenen Methoden verwenden.
Berücksichtigen Sie die folgende Verwendung eines Berechnungsausdruck-Generators content:
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 verwendet der body benutzerdefinierte Vorgang eine unterschiedliche Anzahl von Argumenten unterschiedlicher 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. Dies ist wichtig, wenn ein Typtest einer Eingabe einen stärkeren Typ gegeben hat. Betrachten Sie z. B. den 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)
In jedem Musterfall wird das Eingabeobjekt typgeprüft. Die rechte Seite des as Musters darf nun ein weiteres Muster sein, das sich selbst mit dem Objekt beim stärkeren Typ abgleichen kann.
Dieses Feature implementiert F# RFC FS-1105.
Überarbeitungen der Syntax für Einzüge
F# 6 entfernt eine Reihe von Inkonsistenzen und Einschränkungen in der Nutzung einrückungsbewussten Syntax. Siehe RFC FS-1108. Dadurch werden 10 wichtige Probleme behoben, die von F#-Benutzern seit F# 4.0 hervorgehoben wurden.
In F# 5 war beispielsweise der folgende Code zulässig:
let c = (
printfn "aaaa"
printfn "bbbb"
)
Der folgende Code war jedoch nicht zulässig (er hat eine Warnung erstellt):
let c = [
1
2
]
In F# 6 sind beide zulässig. Dadurch wird F# leicht verständlich und einfacher zu lernen. Der F#-Community-Beitragende Hadrian Tang hat den Weg geebnet, einschließlich bemerkenswerter und äußerst wertvoller systematischer Tests des Features.
Dieses Feature implementiert F# RFC FS-1108.
Zusätzliche implizite Konvertierungen
In F# 6 haben wir die Unterstützung für zusätzliche "implizite" und "typgesteuerte" Konvertierungen aktiviert, wie in RFC FS-1093 beschrieben.
Diese Änderung bringt drei Vorteile:
- Weniger explizite Upcasts sind erforderlich.
- Weniger explizite ganzzahlige Konvertierungen sind erforderlich.
- Erstklassige Unterstützung für implizite Konvertierungen im .NET-Stil wird hinzugefügt.
Dieses Feature implementiert F# RFC FS-1093.
Zusätzliche implizite Upcast-Konvertierungen
F# 6 implementiert zusätzliche implizite Upcast-Konvertierungen. Beispielsweise wurden in F# 5 und früheren Versionen Upcasts für den Rückgabeausdruck benötigt, wenn eine Funktion implementiert wurde, deren Ausdrücke in verschiedenen Verzweigungen unterschiedliche Untertypen hatten, auch wenn eine Typanmerkung vorhanden war. Beachten Sie den folgenden F# 5-Code:
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 jeweils ein TextReader und ein StreamReader, und der Upcast wurde hinzugefügt, um beide Verzweigungen mit dem Typ StreamReader zu versehen. In F# 6 werden diese Upcasts jetzt automatisch hinzugefügt. Dies bedeutet, dass der Code einfacher ist:
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")
Sie können optional 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 ganzzahlige Konvertierungen
In F# 6 werden 32-Bit-Ganzzahlen auf 64-Bit-Ganzzahlen erweitert, wenn beide Typen bekannt sind. Betrachten Sie beispielsweise ein typisches API-Shape:
type Tensor(…) =
static member Create(sizes: seq<int64>) = Tensor(…)
In F# 5 müssen ganzzahlige Literale für int64 verwendet werden:
Tensor.Create([100L; 10L; 10L])
oder
Tensor.Create([int64 100; int64 10; int64 10])
In F# 6 erfolgt die Verbreiterung automatisch von int32 zu int64, von int32 zu nativeint und von int32 zu double, wenn sowohl der Quell- als auch der Zieltyp während der Typinferenz bekannt sind. In Fällen wie den vorherigen Beispielen int32 können Literale verwendet werden:
Tensor.Create([100; 10; 10])
Trotz dieser Änderung verwendet F# in den meisten Fällen weiterhin eine explizite Verbreiterung numerischer Typen. Beispielsweise gilt die implizite Verbreiterung nicht für andere numerische Typen, wie int8 oder int16, oder von float32 zu float64, oder wenn der Quell- oder Zieltyp unbekannt ist. Optional können Sie die Warnung auch aktivieren, um eine Warnung /warnon:3389 an jedem Punkt der impliziten numerischen Verbreiterung anzuzeigen, wie in optionalen Warnungen für implizite Konvertierungen beschrieben.
Erstklassige Unterstützung für . Implizite Konvertierungen im NET-Stil
In F# 6 werden .NET-Konvertierungen "op_Implicit" beim Aufrufen von Methoden automatisch in F#-Code angewendet. In F# 5 musste beispielsweise beim Arbeiten mit .NET-APIs für XML folgendes verwendet XName.op_Implicit werden:
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")
In F# 6 werden Konvertierungen automatisch für Argumentausdrücke angewendet, op_Implicit wenn Typen für Quellausdrücke 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 aktivieren, um an jedem Punkt, an dem Konvertierungen erweitert werden, bei Methodenargumenten eine Warnung /warnon:3395 anzuzeigen, wie in op_Implicit beschrieben.
Hinweis
In der ersten Veröffentlichung von F# 6 war diese Warnnummer /warnon:3390. Aufgrund eines Konflikts wurde die Warnnummer später auf /warnon:3395 aktualisiert.
Optionale Warnungen für implizite Konvertierungen
Typgesteuerte und implizite Konvertierungen können schlecht mit Typableitung interagieren und zu Code führen, der schwieriger zu verstehen ist. Aus diesem Grund gibt es einige Entschärfungen, um sicherzustellen, dass dieses Feature nicht im F#-Code missbraucht wird. Erstens muss sowohl der Quell- als auch der Zieltyp stark bekannt sein, ohne dass Unklarheit oder zusätzliche Typableitung entsteht. Zweitens können Opt-In-Warnungen aktiviert werden, um jede Verwendung impliziter Konvertierungen zu melden, wobei standardmäßig eine Warnung aktiviert ist:
-
/warnon:3388(zusätzlicher impliziter Upcast) -
/warnon:3389(implizite numerische Erweiterung) -
/warnon:3391(op_Implicit bei nicht-methodischen Argumenten standardmäßig aktiviert) -
/warnon:3395(op_Implicit in Methodenargumenten)
Wenn Ihr Team alle Verwendungen impliziter Konvertierungen verbieten möchte, können Sie auch angeben/warnaserror:3388, , /warnaserror:3389, und /warnaserror:3391/warnaserror:3395.
Formatierung für Binäre Zahlen
F# 6 fügt das %B Muster den verfügbaren Formatbezeichnern für binäre Zahlenformate hinzu. Beachten Sie den folgenden F#-Code:
printf "%o" 123
printf "%B" 123
Dieser Code gibt die folgende Ausgabe aus:
173
1111011
Dieses Feature implementiert F# RFC FS-1100.
Verwirft bei Verwendung von Bindungen
F# 6 ermöglicht _ die Verwendung in einer use Bindung, 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 Code einfügt. In F# 6 haben wir ein neues deklaratives Feature hinzugefügt, mit dem Code optional angeben kann, dass, wenn ein Argument als Lambda-Funktion festgelegt wird, dieses Argument immer an Aufrufstandorten inline sein sollte.
Betrachten Sie beispielsweise die folgende iterateTwice Funktion, um ein Array zu durchlaufen:
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 Aufrufstelle ist:
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
Anschließend ergibt der Code nach Inlining und anderen Optimierungen:
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 Lambda-Ausdrucks angewendet. Dieses Feature kann auch verwendet werden, um Schleifenentfaltung und ähnliche Transformationen zuverlässiger zu implementieren.
Eine Opt-In-Warnung (/warnon:3517standardmäßig deaktiviert) kann aktiviert werden, um Orte in Ihrem Code anzugeben, an denen InlineIfLambda Argumente nicht an Lambda-Ausdrücke an Aufrufwebsites gebunden sind. In normalen Situationen sollte diese Warnung nicht aktiviert werden. In bestimmten Arten der Hochleistungsprogrammierung kann es jedoch hilfreich sein, sicherzustellen, dass der gesamte Code inline und flach gestaltet ist.
Dieses Feature implementiert F# RFC FS-1098.
Fortsetzbarer Code
Die task {…} Unterstützung von F# 6 basiert auf einer Grundlage namens resumable CodeRFC FS-1087. Resume-fähiger Code ist eine technische Funktion, die verwendet werden kann, um viele Arten von hochleistungsfähigen asynchronen und zustandsumkehrenden Automaten zu erstellen.
Zusätzliche Sammlungsfunktionen
FSharp.Core 6.0.0 fügt fünf neue Vorgänge zu den Kernsammlungsfunktionen hinzu. Diese Funktionen sind:
- 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 Sequenz aus. Dieser Vorgangstyp ist eine Form eines "Funktionsupdates". Beispiele für die Verwendung dieser Funktionen finden Sie in der entsprechenden Dokumentation, z. B. List.insertAt.
Betrachten Sie beispielsweise das Modell, die Nachricht und die Aktualisierungslogik für eine einfache Anwendung "Todo List", die im Elmish-Stil geschrieben wurde. Hier interagiert der Benutzer mit der Anwendung, generiert Nachrichten und die update Funktion verarbeitet diese Nachrichten, wodurch ein neues Modell erzeugt wird:
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.
Karte hat Schlüssel und Werte
In FSharp.Core 6.0.0 unterstützt der Map Typ jetzt die Schlüssel- und Werteeigenschaften . Diese Eigenschaften kopieren die zugrunde liegende Auflistung nicht.
Dieses Feature ist in F# RFC FS-1113 dokumentiert.
Zusätzliche systeminterne Systeme für NativePtr
FSharp.Core 6.0.0 fügt dem NativePtr-Modul neue systeminterne Elemente hinzu:
NativePtr.nullPtrNativePtr.isNullPtrNativePtr.initBlockNativePtr.clearNativePtr.copyNativePtr.copyBlockNativePtr.ofILSigPtrNativePtr.toILSigPtr
Wie bei anderen Funktionen in NativePtr sind diese Funktionen inlined, und ihre Verwendung gibt Warnungen aus, es sei denn, /nowarn:9 wird verwendet. 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 Einheitenanmerkungen
In F# 6 unterstützen die folgenden Typen oder Abkürzungsaliasen jetzt Unit-of-Measure-Anmerkungen. 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 nicht signierte ganze Zahl wie folgt kommentieren:
[<Measure>]
type days
let better_age = 3u<days>
Dieses Feature ist in F# RFC FS-1091 dokumentiert.
Informationswarnungen für selten verwendete symbolische Operatoren
F# 6 fügt weiche Anleitungen hinzu, die die Verwendung von :=, !, incr, und decr in F# 6 und darüber hinaus denormiert. Die Verwendung dieser Operatoren und Funktionen erzeugt Informationsmeldungen, die Sie auffordern, Den Code durch die explizite Verwendung der Value Eigenschaft zu ersetzen.
Bei der F#-Programmierung können Referenzzellen für heap-zugeordnete änderbare Register verwendet werden. Obwohl sie gelegentlich nützlich sind, sind sie selten in der modernen F#-Codierung erforderlich, da let mutable sie stattdessen verwendet werden können. Die F#-Kernbibliothek enthält zwei Operatoren := und ! zwei Funktionen incr und decr spezifisch für Verweisaufrufe. Das Vorhandensein dieser Operatoren macht Referenzzellen zentraler für die F#-Programmierung, als sie sein müssen, sodass alle F#-Programmierer diese Operatoren kennen müssen. Darüber hinaus kann der ! Operator leicht mit dem not Vorgang in C# und anderen Sprachen verwechselt werden, eine potenziell subtile Quelle von Fehlern beim Übersetzen von Code.
Der Grund für diese Änderung besteht darin, die Anzahl der Operatoren zu reduzieren, die der F#-Programmierer kennen muss, und damit F# für Anfänger vereinfachen.
Betrachten Sie beispielsweise den folgenden F#5-Code:
let r = ref 0
let doSomething() =
printfn "doing something"
r := !r + 1
Zunächst werden Referenzzellen in der modernen F#-Codierung nur selten benötigt, da let mutable normalerweise stattdessen verwendet werden kann.
let mutable r = 0
let doSomething() =
printfn "doing something"
r <- r + 1
Wenn Sie Referenzzellen verwenden, gibt F# 6 eine Informationswarnung aus, die Sie auffordert, die letzte Zeile in r.Value <- r.Value + 1 zu ändern, und leitet Sie zu weiteren Anleitungen zur richtigen Verwendung von Referenzzellen weiter.
let r = ref 0
let doSomething() =
printfn "doing something"
r.Value <- r.Value + 1
Diese Meldungen sind keine Warnungen; sie sind "Informationsmeldungen", die in der IDE- und Compilerausgabe angezeigt werden. F# bleibt abwärtskompatibel.
Dieses Feature implementiert F# RFC FS-1111.
F#-Tools: .NET 6 der Standard für skripting in Visual Studio
Wenn Sie ein F#-Skript (.fsx) in Visual Studio öffnen oder ausführen, wird das Skript standardmäßig mit .NET 6 mit 64-Bit-Ausführung analysiert und ausgeführt. Diese Funktionalität wurde in der Vorschau in den späteren Versionen von Visual Studio 2019 angezeigt und ist jetzt standardmäßig aktiviert.
Um .NET Framework-Skripting zu aktivieren, wählen Sie "Extras>Optionen>F# Tools>F# Interactive" aus. Legen Sie Use .NET Core Scripting auf false fest und starten Sie dann das F# Interactive-Fenster neu. Diese Einstellung wirkt sich sowohl auf die Skriptbearbeitung als auch auf die Skriptausführung aus. Um die 32-Bit-Ausführung für .NET Framework-Skripting zu aktivieren, legen Sie auch 64-Bit F# Interactive auf "false" fest. Es gibt keine 32-Bit-Option für .NET Core-Skripting.
F#-Tools: SDK-Version für Ihre F#-Skripts festlegen
Wenn Sie ein Skript in dotnet fsi einem Verzeichnis ausführen, das eine global.json Datei mit einer .NET SDK-Einstellung enthält, wird die aufgeführte Version des .NET SDK verwendet, um das Skript auszuführen und zu bearbeiten. Dieses Feature ist in den späteren Versionen von F# 5 verfügbar.
Angenommen, es gibt ein Skript in einem Verzeichnis mit der folgenden global.json Datei, die eine .NET SDK-Versionsrichtlinie angibt:
{
"sdk": {
"version": "5.0.200",
"rollForward": "minor"
}
}
Wenn Sie nun das Skript mit dotnet fsi aus diesem Verzeichnis ausführen, wird die SDK-Version berücksichtigt. Dies ist ein leistungsfähiges Feature, mit dem Sie das SDK "sperren" können, das zum Kompilieren, Analysieren und Ausführen Ihrer Skripts verwendet wird.
Wenn Sie Ihr Skript in Visual Studio und anderen IDEs öffnen und bearbeiten, respektieren die Tools diese Einstellung bei der Analyse und Überprüfung 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 einfaches Shebang für script.fsx ist:
#!/usr/bin/env -S dotnet fsi
printfn "Hello, world"
Jetzt kann das Skript direkt mit script.fsx. 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 der Annahme analysieren, dass die neueste Sprachversion verwendet wird.
Entfernen von Legacy-Funktionen
Seit F# 2.0 haben einige veraltete Legacy-Features seit langem Warnungen gegeben. Wenn Sie diese Features in F# 6 verwenden, werden Fehler zurückgegeben, es sei denn, Sie verwenden /langversion:5.0 explizit. Die Features, die Fehler liefern, sind:
- Mehrere generische Parameter mit einem Postfix-Typnamen, z. B.
(int, int) Dictionary. Dies wird zu einem Fehler in F# 6. 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. - Verwendung von Eingaben
*.mlund*.mli. Dies wird zu einem Fehler. - Verwendung von
(*IF-CAML*)oder(*IF-OCAML*). Dies wird zu einem Fehler. - Verwendung von
land, ,lor,lxor,lsl,lsroderasrals Infixoperatoren. Dies sind Infixstichwörter in F#, da sie infix-Schlüsselwörter in OCaml waren und nicht in FSharp.Core definiert sind. Wenn Sie diese Schlüsselwörter verwenden, wird jetzt eine Warnung ausgegeben.
Dadurch wird F# RFC FS-1114 implementiert.