Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Üdvözöljük az F# 11 világában! Ez a kiadás segít elkülöníteni a tartományi modelleket, újrafelhasználni az általános algoritmusokat, összehangolni az aszinkron munkát, és csökkenteni a fordító memóriahasználatát.
- A rekordszétterítés lehetővé teszi a mezők újbóli felhasználását anélkül, hogy a tárolási és alkalmazásmodelleknek közös típust kellene használniuk.
- Az általános algoritmusok bővítménytagjai lehetővé teszik a meglévő típusok számára a műveletek burkoló nélküli megosztását.
- .NET integráció megőrzi a delegáltak metaadatait, és újrafelhasználja az API-dokumentációt.
- Az aszinkron és feladatkezelő segédek biztosítják a megszakítás továbbadását az API-határokon át, és korlátozzák az egyidejű műveletek számát.
- A fordító és a könyvtár fejlesztései csökkentik az ismétlődő elemzések számát, és elkerülhetővé tesznek egyes erőforrás-foglalásokat.
Köszönjük az F#-közösségnek az e változások alapjául szolgáló javaslatokat, megvalósításokat, felülvizsgálatokat és teszteket. A közreműködői hivatkozások az alábbi elemekhez kapcsolódnak.
Note
A példákhoz F# 11 fordító és FSharp.Core 11 szükséges az itt bemutatott funkciókkal. A .NET 11.0.100 SDK-ban az F# 11.2 funkcióihoz <LangVersion>preview</LangVersion> szükséges; lásd: nyelvi beállítások és tervezett SDK-támogatás. A futtatókörnyezet-aszinkron példa további futtatókörnyezeti követelményekkel rendelkezik; előfordulhat, hogy egy korábbi .NET 11 SDK nem tartalmaz minden változást.
Rekordszórások: eltérő modellek ismétlődő leképezések nélkül
A tárolási és alkalmazásmodellek megkülönböztetése érdekében a rekordkiterjesztések ismételt deklarációk nélkül használják újra a megosztott mezőket. Itt a modellek megosztják az ügyfelek adatait, de különböző azonosítótípusokat használnak:
open System
type CustomerId = CustomerId of Guid
type CustomerDetails = { Name: string; PreferredLanguage: string }
type CustomerRow =
{ ...CustomerDetails
Id: string
InternalNote: string }
type Customer =
{ ...CustomerDetails
Id: CustomerId }
...CustomerDetails meződeklarációkat ad hozzá. A határnál másolja az értékeket, ...row míg az átalakítás elemzi az azonosítót:
let toCustomer (row: CustomerRow) =
match Guid.TryParse row.Id with
| true, id -> Ok ({ ...row; Id = CustomerId id }: Customer)
| false, _ -> Error "Invalid customer identifier."
A cél megtartja a megosztott részleteket, lecseréli Id, és kizárja a(z) InternalNote elemet.
Guid.TryParse, nem az oldalpár, hanem az azonosítót ellenőrzi; a helytelen formátumú bemenet Error-t eredményez.
Ez az alkalmazásréteg-leképezési problémát kezeli. Az értékspreadek névvel ellátott és névtelen rekordokat is kombinálnak; a típusspreadek csak névvel ellátott rekordokat hoznak létre. A későbbi mezők felülírják a korábbiakat, a források pedig egyszer, meghatározott sorrendben futnak le. Lásd a rekordterítő operátorok című témakört az összeállítási példákkal és a közös fejlődés kockázataival kapcsolatban.
Köszönet @brianrourkeboll részére a rekord spreadekért.
Bővítménytagok általános algoritmusokhoz, operátorokhoz és n-esekhez
Az algoritmus meglévő típusok közötti megosztásához az F# 11.2 lehetővé teszi, hogy a bővítménytagok kielégítsék a statikusan feloldott típusparaméter (SRTP) korlátozásait. Egy átalakítás például burkolótípusok nélkül is kezelhet listákat és opciókat.
Note
A .NET 11.0.100 SDK-ban engedélyezze a(z) <LangVersion>preview</LangVersion> elemet ott, ahol a bővítmények feloldása történik, és nyissa meg a moduljukat. Lásd a könyvtár követelményeit.
Átalakítás megosztása listák és beállítások között
A kódtár map elemének hatókörében az alkalmazás megtisztíthatja bármelyik reprezentációt, módosíthatja az elemtípusokat, és átalakításokat állíthat össze:
let inline cleanNames values =
map (fun (name: string) -> name.Trim().ToUpperInvariant()) values
let batch: string list = cleanNames [ " Ada "; " grace " ]
let optional: string option = cleanNames (Some " linus ")
let missing: string option = cleanNames (None: string option)
let lengths: int list = map String.length batch
let nested: int option list = map (map String.length) [ Some "abc"; None ]
printfn "%A; %A; %A" batch optional missing
printfn "%A; %A" lengths nested
// ["ADA"; "GRACE"]; Some "LINUS"; None
// [3; 5]; [Some 3; None]
A Structural.Adapters adapterei ismert műveleteket használnak, ahelyett hogy új tárolók használatát kényszerítenék ki:
type List<'T> with
static member Map(source: 'T list, mapping: 'T -> 'U) : 'U list =
List.map mapping source
type Option<'T> with
static member Map(source: 'T option, mapping: 'T -> 'U) : 'U option =
Option.map mapping source
A Structural.Algorithms megosztott függvény a bemeneti típustól egy statikus Map tagot kér:
let inline map (mapping: 'T -> 'U) (source: ^Input) : ^Output =
(^Input :
(static member Map: ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
^Input és ^Output statikusan feloldott típusok. Minden egyes konkrét hívásnál a fordítóprogram kiválasztja a megkövetelt szignatúrával rendelkező tagot. A bővítmények nem adnak hozzá interfészimplementációt. A teljes alkalmazás mindkét modult megnyitja.
Operátorok, környezet és kimeneti típusok
Ugyanez a mechanizmus támogatja a tuple-operatorokat és a környezettovábbítást, valamint a kimenetvezérelt konstrukciót. A natív tuple-fejlécekhez az F# 11.2 funkciót engedélyezni kell a deklarációiknál, valamint a bővítménymegoldási híváshelyeken is.
Egy külön kiegészítés lehetővé teszi, AllowOverloadOnReturnTypehogy egy factory deklarálja a túlterheléseket a visszatérési típusaik alapján megkülönböztetve:
type Inject =
[<AllowOverloadOnReturnType>]
static member Pure(value: 'T) : 'T list = [value]
[<AllowOverloadOnReturnType>]
static member Pure(value: 'T) : 'T option = Some value
let batch: string list = Inject.Pure "ready"
let optional: string option = Inject.Pure "ready"
// ["ready"] and Some "ready"
Ehhez a Core 11 attribútumhoz nincs szükség előnézetre. Az eredményannotáció túlterhelt függvényváltozatot jelöl ki; nélküle a hívás továbbra is nem egyértelmű. Lásd: Kiválasztás visszatérési típus szerint.
Köszönjük @gusty-nak az általános programozási támogatás kiterjesztését.
.NET integráció és a fejlesztési élmény
A közvetlen delegáltak megőrzik a kezelőobjektum valódi kontraktusát
A kezelőnevek és kötési attribútumok keretrendszerek számára való felfedéséhez az F# 11 közvetlenül egy kompatibilis elnevezett függvényt célozhat meg burkoló helyett. ASP.NET Core Minimális API-k ezután elolvashatják az útvonal-, szolgáltatás- és fejlécszerződést:
open System
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.DependencyInjection
type ShipmentStore() =
member _.Status trackingId =
if trackingId = "SHP-1042" then "Dispatched" else "Unknown"
let status
(trackingId: string)
([<FromServices>] store: ShipmentStore)
([<FromHeader(Name = "X-Customer")>] customer: string) =
$"{customer}: {trackingId} is {store.Status trackingId}"
let handler = Func<string, ShipmentStore, string, string>(status)
Tekintse meg a futtatható projektet és az építési/kompatibilitási szabályokat. A rögzítésekhez és az argumentumok kiigazításához továbbra is burkoló szükséges.
Köszönet a közvetlen meghatalmazottak @kerams.
XML-dokumentáció újrafelhasználása
Ha egyszer szeretné fenntartani a megosztott API-megjegyzéseket, helyezze őket a következő helyre shared.xml:
<docs>
<tracking>
<remarks>An unrecognized tracking identifier has status Unknown.</remarks>
</tracking>
</docs>
Ha GenerateDocumentationFile engedélyezve van, az F# 11 kibővül <include> a kibocsátott tagbejegyzésekkel:
/// <summary>Find the latest status of a shipment.</summary>
/// <include file="shared.xml" path="/docs/tracking/*"/>
let status trackingId =
if trackingId = "SHP-1042" then "Dispatched" else "Unknown"
/// <summary>Find the latest statuses of several shipments.</summary>
/// <include file="shared.xml" path="/docs/tracking/*"/>
let statuses trackingIds =
trackingIds |> List.map (fun id -> id, status id)
A belefoglalási implementáció mindkét leírást frissíti egy töredékből. Az eszközfeloldó külön-külön elérhetővé teszi az alapleírásokat <inheritdoc/>; a fordító ezt a címkét hagyja a dokumentáció felhasználói számára. Példákat és megoldási szabályokat az XML-dokumentációban talál.
Az FSharp.Core megosztott XML-dokumentációjának @T-Gro-nak köszönhetően.
Beágyazott függvények hibakeresése nem optimalizált buildekben
A beágyazott segédfüggvény argumentumainak vizsgálatához állítson be egy töréspontot a(z) let total elemre egy nem optimalizált buildben, majd lépjen be a(z) addFee függvénybe. Az F# 11 ezekben a verziókban mostantól a meghívható metódusokat részesíti előnyben:
let inline addFee (fee: decimal) (amount: decimal) =
let total = amount + fee
total
let invoiceTotal = addFee 2m 40m
printfn "%M" invoiceTotal
// 42
Az optimalizált buildek megtartják az inlininget. Egyes szerkezeteknek továbbra is bővülniük kell. A korlátokkal és a --always-inline vezérlővel kapcsolatban lásd: Soron belüli függvények hibakeresése.
Aszinkron és feladatkoordináció
Az F#-munkafolyamatok tevékenységalapú API-kkal való összekapcsolásához az FSharp.Core 11 megszakításkezelő hidakat, korlátozott méretű kötegeket és eredményátalakításokat ad hozzá.
Kösse a függőben lévő I/O-t, ne csak az eredménygyűjteményhez
A nagy mennyiségű olvasás több munkát indíthat el, mint amennyi egy alkalmazásnál folyamatban lehet. Annak eldöntéséhez, hogy mikor kezdődik a feladatalapú munka, a koordinátornak factory-kra van szüksége, nem pedig a már megkezdett feladatokra:
open System.IO
open System.Threading
let readFiles (paths: seq<string>) (ct: CancellationToken) =
paths
|> Seq.map (fun path ->
fun token -> File.ReadAllTextAsync(path, token))
|> Task.parallelLimit 4 ct
Legfeljebb négy olvasási művelet fut egyszerre; az eredmények megtartják a bemeneti sorrendet. A meghiúsulás a megadott tokeneken keresztül testvértörlést kér. Ez korlátozza az egyidejűséget, nem pedig a másodpercenkénti kéréseket. A szekvenciális és unit eredményű változatokért lásd: Aszinkron és taskfüggvények.
Őrizze meg a megszakítást és a mögöttes kivételt a határon át
Amikor egy munkafolyamat külső munkát indít, a tokennek ezzel a munkával együtt kell továbbhaladnia.
Async.StartTaskImmediate átadja a futó munkafolyamat tokenjét a feladatgyárnak, és megvárja a befejezést:
open System.IO
let tryReadFile path =
async {
try
let! contents =
Async.StartTaskImmediate(fun ct -> File.ReadAllTextAsync(path, ct))
return Some contents
with :? FileNotFoundException ->
return None
}
Egyetlen feladat hibája jut el ehhez a kezelőhöz mögöttes FileNotFoundException formájában. Már létrehozott feladat vagy értéket visszaadó feladat esetén használja a(z) Async.Await elemet; a régebbi Async.AwaitTask megtartja a kivételekbe csomagoló működését.
A feladatalapú hívók számára Task.startAsyncImmediate token workflow biztosítja a reverse bridge-et. Az első aszinkron felfüggesztésig a hívó szálon kezdődik.
Illeszkedő segédek használata rövid átalakításokhoz
Ha egy eredményt teljes számítási kifejezés nélkül szeretne átalakítani, használja a hozzá tartozó segédfüggvényeket a(z) Microsoft.FSharp.Control elemben. Például olvassa el a fájlt, kérdezze le a hosszát, és adjon vissza egy általános hibát a következő módon Error:
open System.IO
open System.Threading
let fileLength (path: string) (ct: CancellationToken) =
File.ReadAllTextAsync(path, ct)
|> Task.map String.length
|> Task.catch
Az Ok 8-t tartalmazó fájl Report 1-t eredményez; a hiányzó fájl egy Error-t ad, amely FileNotFoundException-at tartalmaz. A megszakítás továbbra is továbbterjed.
Async és megfelelő bind, map és hibakezelő segédfüggvényeket kínál; lásd: ValueTask. Használjon számításkifejezést elágazásokhoz vagy több egymástól függő értékhez.
A ValueTask-segítőknek a Core netstandard2.1 vagy net10.0 buildjére és egyszeri felhasználásra van szükségük.
Köszönet @bartelink-nek az aszinkron/feladat API-hoz nyújtott hozzájárulásokért.
Újradobás aszinkron hibajelentés után
Az operatív naplózásnak anélkül kell információt hozzáadnia, hogy módosítaná, mit kezel a hívó, vagy elrejtené, hol kezdődött a hiba. A számítási-kifejezéskezelők most már akkor is használhatják a reraise () elemet, miután await-olják a naplózót:
Note
A számítási kifejezés újradobása egy F# 11.2-es funkció. A .NET 11.0.100 SDK-ban engedélyezze a(z) <LangVersion>preview</LangVersion> elemet.
open System
open System.IO
open System.Threading.Tasks
let readReport (logFailure: exn -> Task) path =
task {
try
return! File.ReadAllTextAsync(path)
with :? IOException as error ->
do! logFailure error
return reraise ()
}
A sikeres bejelentkezés után ugyanaz a kivétel és az eredeti dobáshely adatai terjednek tovább. A naplózó hibája lecserélheti az eredetit. Ez az aszinkron megfigyelhetőségi igényt kezeli futtatásidejű aszinkronitás nélkül. Lásd: Újradobás számítási kifejezésből.
Köszönjük @xperiandri támogatását.
Az FSharp.Core modern .NET
Ha modern API-kat szeretne használni a régebbi célok elvetése nélkül, az FSharp.Core hozzáadja net10.0 a netstandard2.0netstandard2.1. A NuGet a kompatibilis verziót választja ki. A frissített eszközcsomagolás a feladatalapú aszinkron felszabadítást is lehetővé teszi az F# Interactiveban, mint a lefordított projektekben. Lásd a FSharp.Core célkeretrendszereit.
@T-Gro-ért A modern Core célzásnak és SDK-eszközcsomagolásnak köszönhetően.
Futásidejű aszinkronitás összeállítók készítőinek
A builderek szerzői engedélyezhetik, hogy a futtatókörnyezet a fordító által létrehozott állapotgépek használata helyett felfüggessze és folytassa a megjelölt metódusokat. A kísérleti kódtár által definiált builder számítási kifejezésként teszi elérhetővé a mechanizmust:
let readManifest (path: string) =
runtimeTask {
let! text = System.IO.File.ReadAllTextAsync path
return text.Length
}
Note
Ez a kísérleti builder az F# 11.2 egyik olyan funkcióját használja, amely lehetővé teszi az inline implementáció meghatározását vagy kibontását; a .NET 11.0.100 SDK-ban engedélyezze az előzetes funkciókat. Emellett a Core 11 buildjéhez net10.0 és hivatkozásaihoz, valamint egy futtatókörnyezethez is szükség van, amely támogatja a futtatókörnyezetet. Az ellenőrzött futtatókörnyezet-/referencia-kombináció itt a .NET 11 RC1. Csak .NET 10-et célozni nem elegendő. Lásd Futtatókörnyezeti aszinkron kísérletek.
Az FSharp.Core nem tartalmazza ezt a mintát általános célú builderként. A szokásos task és async kód nem vált automatikusan rá, és a már lefordított, feladatvisszaadó API-k hívóinak nincs eleve szükségük previewra.
Köszönet @majocha-nak a futásidejű aszinkronért.
Natív AOT-barát szöveg és kétdimenziós tömbök
A natív AOT támogatásához az F# 11 eltávolítja a reflexióalapú formázást és a dinamikus foglalási követelményeket a gyakoribb szöveg- és tömbműveletekből.
Értékek nyomtatása és sztringek létrehozása redundáns formátumréteg nélkül
Ha már rendelkezik sztringgel, nincs szükség egy "%s" formátumra csak azért, hogy leírja. Az új Core-függvények, a print és a printn, értékeket fogadnak el az F# string-konverzióján keresztül; a printn új sort fűz hozzá:
let report (processed: int) (total: decimal) (elapsed: TimeSpan) : string =
$"{processed} items, total {total:F2}, elapsed {elapsed.TotalMilliseconds:F0} ms"
printn (report 12 145.50m (TimeSpan.FromMilliseconds 250.0))
// 12 items, total 145.50, elapsed 250 ms
A sztringinterpoláció több esetben használ közvetlen átalakítást és String.Concat-t. A(z) {total:F2} típusú .NET-formázási helyőrzők invariáns formázást használnak, és boxingolják az értéket; a(z) %A és a pontosságmegadást tartalmazó printf-formák esetében továbbra is szükség lehet printf-formázásra. Válasszon egy konkrét kultúrát a lokalizált kimenethez.
A --reflectionfreerekordok és az uniók szintén generált ToString kimenetet kapnak. A kulturális példákat és a támogatott útvonalakat lásd a Interpoláció és natív AOT című témakörben.
Köszönet @bbatsov-nak a nyomtatási függvényekért és @charlesroddie-nak az interpoláció megvalósításáért.
A szokásos, nulla alapú rács műveleteinek megtartása
Egy nullaindextől kezdődő rácsnak nem szabadna helyettesítő Array2D modult igényelnie pusztán azért, hogy elkerülje a dinamikuskód-allokációs útvonalat. A frissített Core-implementációk támogatják a jól ismert inicializálást és átalakítást:
let grid = Array2D.init 3 4 (fun row column -> row * 4 + column)
let doubled = grid |> Array2D.map (fun value -> value * 2)
let snapshot = Array2D.copy doubled
printn $"{snapshot.GetLength(0)} x {snapshot.GetLength(1)}; last = {snapshot[2, 3]}"
// 3 x 4; last = 22
Array2D.create, init és rebase használják a nulla alapú foglalási útvonalat a Core-buildekben. A korlátmegőrző map, mapi és copy használhat egy újabb .NET foglalási API-t a net10.0 buildben; a .NET Standard buildek megtartják tartalék megoldásukat. A nem nulla alapú tömbök nincsenek elavultként megjelölve, de a natív foglalási korlátozások megmaradnak.
A lefoglalási útvonalakról és a fennmaradó korlátozásokról lásd a kétdimenziós tömböket és a natív AOT-t. Ellenőrizze a teljes alkalmazás közzétételi diagnosztikáját.
Köszönet @T-Gro-nak az Array2D fejlesztésekért.
Kevesebb megőrzött memória és kevesebb ismétlődő munka
Az F# 11 csökkenti az ismétlődő fordítóelemzést és néhány alkalmazásfoglalást. Ezek különböző számítási feladatokat érintenek.
Hivatkozott kódtárak megosztása projektek között
A megosztott bináris függőségek ismétlődő példányainak elkerülése érdekében a nyelvi szolgáltatás megoszthatja az alkalmas importált függőségi gráfokat a projektek között.
Az implementáló PR memória-megtartási kísérletében a tízprojektből álló ReSharper.FSharp-megoldás 1547,2 MB-ról 1002,2 MB-ra csökkent a megosztás engedélyezésével. Ez az adott terhelés be/ki jellegű mérése, nem pedig általános F# 10-ről 11-re csökkentés. A közös bináris hivatkozások helyett a projekthivatkozások által dominált megoldások sokkal kisebb nyereséget láthatnak.
A metaadatok beolvasása és a soron belüli specializáció szintén csökkentik az átmeneti allokációkat, amelyek egy külön mérőszámot képeznek. A hatókörrel és vezérlőkkel kapcsolatban lásd: Tooling performance.
Köszönjük @auduchinok-nak/nek a megosztott kódtárak importálását.
Önálló munka fordítása párhuzamosan alapértelmezés szerint
A párhuzamos fordítás alapértelmezés szerint engedélyezve van, a determinisztikus kimenet és a forrásrend szabályai megmaradnak. A túlterheléses gyorsítótárazás és az őrfeltételes minták fejlesztései elkerülik az egyéb ismételt munkát. A Visual Studio/FCS emellett csökkenti a változatlan dokumentumok elemzését, és korlátozza a párhuzamos ellenőrzések számát; lásd: Az eszközök teljesítménye.
A visszahívás és az üres eredményű lefoglalási többletterhelés elkerülése
A kiválasztott List és Array függvények mostantól inline callbackeket támogatnak. A saját beágyazott segítőidhez OptimizeClosureIfNotInlined egyszer egy átlátszatlan, curried visszahívást adaptál:
let inline foldItems
([<InlineIfLambda; OptimizeClosureIfNotInlined>] folder)
state
(items: 'T[]) =
let mutable total = state
for item in items do
total <- folder total item
total
Más lefoglalások is megmaradhatnak. A követelményekért lásd: A kurizott callbackek optimalizálása.
Az üres eredmények is a sikeres működés gyakori jelei. Az FSharpLintet motiváló munkaterhelés ismételten olyan szabályokat kombinált, amelyek nem adtak figyelmeztetést. A Core mostantól még több műveletben újrafelhasználja a megosztott üres tömböket:
let checkTitle (title: string) =
if String.IsNullOrWhiteSpace title then [|"A title is required."|]
else Array.empty
let warnings = ["Introduction"; "Installation"] |> List.toArray |> Array.collect checkTitle
let sharedEmpty = obj.ReferenceEquals(warnings, Array.empty<string>)
// true: no new empty result array
A módosítás eltávolítja a redundáns üres tömbobjektumokat, nem pedig a folyamat minden foglalását. Ne hagyatkozzon arra, hogy a különálló üres eredmények különálló referencia-identitással rendelkeznek.
@T-Gro A beágyazott gyűjtemények visszahívásainak és a megosztott üres tömböknek köszönhetően.
Pontosabb API-hívások és mindennapi kényelem
Nevek megkövetelése, ha a létrehozott paramétersorrend megváltozhat
A generált API-k csendes paramétersorrend-módosításokkal szembeni védelméhez a szerzőnek elnevezett argumentumokat kell megadnia:
Note
Az enforcement egy F# 11.2-funkció; a .NET 11.0.100 SDK-ban engedélyezze az előnézetet. Rendelkezésre álló System.Diagnostics.CodeAnalysis.RequireNamedArgumentsAttribute definícióra is szükség van. A teljes minta egy kompatibilitási definíciót biztosít azokhoz a hivatkozásokhoz, amelyekből ez hiányzik.
open System.Diagnostics.CodeAnalysis
type Query =
[<RequireNamedArguments>]
static member Execute(numerator: decimal, denominator: decimal) =
numerator / denominator
let ratio = Query.Execute(numerator = 3m, denominator = 4m)
// 0.75M; Query.Execute(3m, 4m) is rejected.
A deklaráció átrendezése megőrzi az elnevezett hívás eredményét; 0.75Ma rendszer elutasít egy pozícióhívást. A generált API-használati esethez a szolgáltatónak ki kell adnia az annotációt.
Már burkolt általános paraméter felismerése
A meglévő tevékenységek egyszerű eredményértékbe csomagolásának elkerülése érdekében az új végső megoldás túlterhelési szabálya 'T inkább a csupasz Task<'T> értéket részesíti előnyben:
Note
A legkonkrétabb tiebreaker és a túlterhelési prioritás működése az F# 11.2 funkciói; a .NET 11.0.100 SDK-ban engedélyezze az előzetes funkciókat.
open System.Threading.Tasks
let pending = Task.FromResult 42
let wrapped = ValueTask<_>(pending)
let answer: int = wrapped.Result
// ValueTask<int>, not ValueTask<Task<int>>
Az eredmény ValueTask<int>, nem ValueTask<Task<int>>. A szabály korlátait lásd: Overload selection.
Új túlterhelés előnyben részesítése a régi hozzáférési pont eltávolítása nélkül
Előfordulhat, hogy egy könyvtár megtart egy régi diagnosztikai módszert a meglévő bináris fájlokhoz, miközben hozzáad egy túlterhelt függvényváltozatot, amely tartalmazza a hívó forráshelyét.
OverloadResolutionPriorityAttribute egyértelművé teszi ezt a beállítást az újonnan lefordított hívók számára:
open System.Runtime.CompilerServices
type Check =
static member That(condition: bool) =
if condition then "OK" else "Check failed."
[<OverloadResolutionPriority(1)>]
static member That(condition: bool, [<CallerLineNumber>] ?line: int) =
if condition then "OK" else $"Check failed at line {defaultArg line 0}."
let stock = 0
let diagnostic = Check.That(stock > 0)
// The diagnostic includes the caller's source line.
A változatlan hívás a sorérzékeny túlterhelt változatot választja ki. A hatókörre és kompatibilitásra vonatkozó szabályokat lásd itt: túlterhelés kiválasztása.
A .NET feltételes nullkezelési ígéreteinek használata
Ha a fájl elérési útja nem null értékű, a Path API nullázható eredménye nem kényszeríthet olyan ellenőrzésre, amelyet a saját szerződése eleve kizár. Az F# 11 a meglévő .NET NotNullIfNotNull garanciát veszi figyelembe: a nem nullként megjelölt bemenet nem null eredményt jelent.
open System.IO
let fileName: string = Path.GetFileName("reports/annual.csv")
let extension: string = Path.GetExtension(fileName)
printn (extension.ToUpperInvariant())
// .CSV
let fileNameOf (path: string | null) : string | null =
Path.GetFileName path
A(z) <Nullable>enable</Nullable>engedélyezése. A null értékű bemenetek továbbra is null értékű kezelésre szorulnak; lásd a feltételes visszaküldési szerződéseket. A korlátozás nélküli C# T? API-khoz használja a külön Unchecked.withNull segítőt.
Köszönet @kerams-nak a feltételes nullázhatóság támogatásáért.
Kisebb nyelvi fejlesztések
Ha .NET konstruktorszintaxissal szeretne rekordtípust példányosítani, használja az F# 11.2 rekordkonstruktorokat:
type Person = { Name: string; Age: int }
let person = Person(Name = "Ada", Age = 36)
A névvel ellátott argumentumok elkerülik a mezőrendtől való függőséget. Köszönjük, @charlesroddie-nak ezt a funkciót.
Feltételes forrás esetén a #elif elkerüli a beágyazott #if csoportokat:
#if EU_WAREHOUSE
let dispatchTimeZone = "Europe/Paris"
#elif US_WAREHOUSE
let dispatchTimeZone = "America/New_York"
#else
let dispatchTimeZone = "UTC"
#endif
System.Console.WriteLine(dispatchTimeZone)
Az első egyező ág nyer. A mintaprojekt definiálja a(z) EU_WAREHOUSE elemet, és kiírja a(z) Europe/Paris elemet; ha egyik szimbólum sincs definiálva, a kimenet UTC.
Kapcsolódó eszközökhöz és interop esetekhez:
- Az interaktív eszközlánc azonosításához használja
#versiona . - Ha külső hosttal szeretné megosztani a forrást, az F# a csomag- vagy összeállítási utasítások értelmezése nélkül fogadja el
#:a host-direktívasorokat. - A redundáns interfész-deklarációk elkerülése érdekében használja a származtatott interfész alapértelmezett implementációját.
- Az örökölt állapot normál lezáráson belüli olvasásához használja a védett alapmezők új támogatását.
Frissítés előtt
A frissítéskor tartsa szem előtt ezeket a jelentős változásokat:
| Érintett kód | Action |
|---|---|
Tárak fájlokkal .fsi |
Kényszerített szerződésattribútumok másolása aláírásokra; a kihagyások mostantól FS3888-hibák. |
| Bővítmények által támogatott beágyazott könyvtárak | Tekintse át a kikövetkeztetett aláírásokat és a gyártói/fogyasztói követelményeket. Az F# 11.2 típuskövetkeztetése általánosabb korlátozásokat is megtarthat. |
| Példánymetódus-meghatalmazottak | Ellenőrizze a fogadó objektumokat a közvetlen konstrukció előtt, amikor most már null értékű fogadó objektum miatti hibák jelentkeznek. |
| Lokalizált, interpolált kimenet | A .NET-formátumhelyek invariáns kultúrát használnak. Válasszon megadott kultúrát, ha honosított kimenet a cél. |
Egyéni építők final do! |
A kötések és egységek kiegészítése; a final do! már nem választja ki a final-forwarding tagokat. |
Befejezetlen let! |
Adja hozzá a következő számítási törzset; a hiányos kötés mostantól közvetlenebb diagnosztikai üzenetet is ad. |
| Régebbi nyelvi beállítások | A támogatott számozott verziók az F# 8-nál kezdődnek; a nem szigorú behúzási mód el lett távolítva. Lásd : Nyelvi verzió és behúzás. |
| Enum bitenkénti műveletek | egész típusú háttértárral rendelkező enumokat használjon; a rendszer elutasítja az érvénytelen háttértípusokat. |