Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
F# 11'e hoş geldiniz! Bu sürüm, etki alanı modellerini ayrı tutmanıza, genel algoritmaları yeniden kullanmanıza, zaman uyumsuz çalışmayı koordine edip derleyici bellek kullanımını azaltmanıza yardımcı olur.
- Kayıt, depolama ve uygulama modellerini bir türü paylaşmaya zorlamadan alanları yeniden kullanma yayma.
- Genel algoritmalardaki uzantı üyeleri , mevcut türlerin sarmalayıcılar olmadan işlemleri paylaşmasına olanak sağlar.
- .NET tümleştirmesi temsilci meta verilerini korur ve API belgelerini yeniden kullanır.
- Zaman uyumsuz ve görev yardımcıları API sınırları boyunca iptali taşır ve eşzamanlı çalışmayı sınırlar.
- Derleyici ve kitaplık geliştirmeleri yinelenen çözümlemeyi azaltır ve bazı ayırmalardan kaçınılır.
Bu değişikliklerin arkasındaki teklifler, uygulamalar, incelemeler ve testler için F# topluluğuna teşekkür ederiz. Katkıda bulunan bağlantıları aşağıdaki özelliklere eşlik eder.
Note
Örneklerde, gösterilen özellikleri içeren bir F# 11 derleyicisi ve FSharp.Core 11 gerekir. .NET 11.0.100 SDK'sında F# 11.2 özellikleri gereklidir<LangVersion>preview</LangVersion>; bkz. dil ayarları ve planlanan SDK desteği. Çalışma zamanı zaman uyumsuz örneği ek çalışma zamanı gereksinimlerine sahiptir; yalnızca önceki bir .NET 11 SDK'sı her değişikliği içermeyebilir.
Kayıt genişletmeleri: tekrarlayan eşlemeler olmadan ayrı modeller
Depolama ve uygulama modellerini ayrı tutmak için record spread yapıları ortak alanları tekrarlı bildirim tanımları olmadan yeniden kullanır. Burada modeller müşteri ayrıntılarını paylaşır ancak farklı tanımlayıcı türleri kullanır:
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 alan bildirimlerine katkıda bulunur. Sınırda, ...row dönüştürme tanımlayıcıyı ayrıştırırken değerleri kopyalar:
let toCustomer (row: CustomerRow) =
match Guid.TryParse row.Id with
| true, id -> Ok ({ ...row; Id = CustomerId id }: Customer)
| false, _ -> Error "Invalid customer identifier."
Hedef paylaşılan ayrıntıları tutar, öğesini değiştirir Idve dışlar InternalNote.
Guid.TryParse, spread değil, tanımlayıcıyı doğrular; hatalı biçimlendirilmiş giriş üretir Error.
Bu, uygulama katmanı eşleme sorununu giderir. Değer yayılmaları, adlandırılmış ve anonim kayıtları da birleştirir; tür spreadleri yalnızca adlandırılmış kayıtlar oluşturur. Sonraki alanlar kazanır ve kaynaklar sırayla bir kez çalışır. Oluşturma örnekleri ve paylaşılan evrim riskleri için bkz. Kayıt yayma işleçleri .
Rekor farklar için @brianrourkeboll'a teşekkürler.
Genel algoritmalar, işleçler ve demetler için uzantı üyeleri
F# 11.2, mevcut türler arasında bir algoritmayı paylaşmak için uzantı üyelerinin statik olarak çözümlenen tür parametresi (SRTP) kısıtlamalarını karşılamasına olanak tanır. Örneğin, bir dönüştürme sarmalayıcı türleri olmadan listeleri ve seçenekleri işleyebilir.
Note
.NET 11.0.100 SDK'sında uzantıların çözümlendiği yeri etkinleştirin <LangVersion>preview</LangVersion> ve modüllerini açın. Bkz. kitaplık gereksinimleri.
Dönüşümleri listeler ve seçenekler arasında paylaşma
Kitaplığın map kapsamı dahilindeyken uygulama her iki gösterimi de temizleyebilir, öğe türlerini değiştirebilir ve dönüştürmeler oluşturabilir:
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]
Structural.Adapters içindeki bağdaştırıcılar, yeni kapsayıcılar dayatmak yerine tanıdık işlemler kullanır:
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
Structural.Algorithms içindeki paylaşılan işlev, giriş türünden statik bir Map üyesi ister:
let inline map (mapping: 'T -> 'U) (source: ^Input) : ^Output =
(^Input :
(static member Map: ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
^Input ve ^Output statik olarak çözümlenmiş türlerdir. Her somut çağrıda, derleyici gerekli imzaya sahip üyeyi seçer. Uzantılar arabirim uygulaması eklemez.
Tam uygulama her iki modülü de açar.
İşleçler, bağlam ve çıkış türleri
Aynı mekanizma demet işleçlerini ve bağlam yaymayı ve çıkışa yönelik oluşturmayı destekler. Yerel tuple başlıklarının bildirimlerinde ve uzantı çözümleme çağrı noktalarında F# 11.2 özelliğinin etkinleştirilmesi gerekir.
Ayrı bir ek olarak, AllowOverloadOnReturnType, bir fabrikanın dönüşleriyle ayırt edilen aşırı yüklemeler bildirmesine olanak tanır:
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"
Bu Core 11 özniteliği önizleme gerektirmez. Sonuç ek açıklama bir aşırı yük seçer; bu olmadan çağrı belirsiz kalır. Bkz. Dönüş türüne göre seçme.
@gusty'ye genel programlama desteğini genişlettiği için teşekkürler.
.NET tümleştirmesi ve geliştirme deneyimi
Doğrudan delegeler işleyicinin gerçek kontratını korur
İşleyici adlarını ve bağlama özniteliklerini çerçevelere göstermek için F# 11, uyumlu bir adlandırılmış işlevi sarmalayıcı yerine doğrudan hedefleyebilir. ASP.NET Core Minimum API'ler yol, hizmet ve üst bilgi sözleşmesini okuyabilir:
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)
Çalıştırılabilir proje ve yapı/uyumluluk kurallarına bakın. Yakalamalar ve bağımsız değişken uyarlaması yine de sarmalayıcılar gerektirebilir.
Doğrudan temsilciler için @kerams sayesinde.
XML belgelerini yeniden kullanma
Paylaşılan API açıklamalarını tek bir yerde tutmak için bunları shared.xml içine yerleştirin:
<docs>
<tracking>
<remarks>An unrecognized tracking identifier has status Unknown.</remarks>
</tracking>
</docs>
Etkin GenerateDocumentationFile olduğunda, F# 11 yayılan üye girişlerine genişletir <include> :
/// <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)
Ekleme uygulaması her iki açıklamayı da bir parçadan güncelleştirir. Ayrıca , araç çözümleyicisi için <inheritdoc/>temel açıklamaları kullanıma sunar; derleyici bu etiketi belge tüketicileri için bırakır. Örnekler ve çözüm kuralları için XML belgelerine bakın.
FSharp.Core'da paylaşılan XML belgeleri için @T-Gro sayesinde.
İyileştirilmemiş derlemelerde satır içi fonksiyonlarda hata ayıklama
Inline helper argümanlarını incelemek için optimize edilmemiş bir derlemede let total üzerinde bir kesme noktası ayarlayın ve addFee içine adım atın. F# 11 artık şu derlemelerde çağrılabilir yöntemleri tercih ediyor:
let inline addFee (fee: decimal) (amount: decimal) =
let total = amount + fee
total
let invoiceTotal = addFee 2m 40m
printfn "%M" invoiceTotal
// 42
İyileştirilmiş derlemeler, inlining'i korur. Bazı yapılar yine de genişlemelidir. Bu sınırlar ve --always-inline denetimi için Satır içi işlevlerde hata ayıklama bölümüne bakın.
Eşzamansızlık ve görev eşgüdümü
F# iş akışlarını görev tabanlı API'lerle bağlamak için FSharp.Core 11, iptali dikkate alan köprüler, sınırlı toplu işlem grupları ve sonuç dönüşümleri ekler.
Yalnızca sonuç koleksiyonunu değil, bekleyen G/Ç'yi de sınırlandırın
Büyük bir okuma işlemleri grubu, bir uygulamanın aynı anda yürütmesi gerekenden daha fazla iş başlatabilir. Görev tabanlı çalışmanın ne zaman başlayacağını belirlemek için bir koordinatör, zaten başlamış görevlere değil, fabrikalara ihtiyaç duyar:
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
En fazla dört okuma işlemi aynı anda yürütülür; sonuçlar giriş sırasını korur. Bir hata, verilen belirteçler üzerinden kardeş iptalini talep eder. Bu, saniye başına istekleri değil eşzamanlılığı sınırlar. Ardışık ve birim sonuçlu varyantlar için bkz. Async ve görev işlevleri.
İptali ve altta yatan istisnayı sınırın ötesinde koruyun
Bir iş akışı dış çalışmayı başlattığında token’ı bu çalışmayla birlikte hareket etmelidir.
Async.StartTaskImmediate çalışan iş akışının belirtecini görev fabrikasına iletir ve tamamlanmasını bekler:
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
}
Tek bir görev hatası, altta yatan FileNotFoundException olarak bu işleyiciye iletilir. Önceden oluşturulmuş bir görev veya değer görevi için Async.Await kullanın; eski Async.AwaitTask görev özel durum sarmalama davranışını korur.
Görev tabanlı çağırıcılar için Task.startAsyncImmediate token workflow geri köprülemeyi sağlar. Yürütme, ilk asenkron askıya alma noktasına kadar çağıran iş parçacığında başlar.
Kısa dönüşümler için eşleşen yardımcıları kullanın
Tam hesaplama ifadesi olmadan bir sonucu dönüştürmek için Microsoft.FSharp.Control içindeki ilgili yardımcıları kullanın. Örneğin, bir dosyayı okuyun, uzunluğunu alın ve sıradan bir hatayı Error olarak döndürün:
open System.IO
open System.Threading
let fileLength (path: string) (ct: CancellationToken) =
File.ReadAllTextAsync(path, ct)
|> Task.map String.length
|> Task.catch
Report 1 içeren bir dosya Ok 8 oluşturur; eksik bir dosya, Error içeren bir FileNotFoundException oluşturur. İptal yine de iletilir.
Async ve ValueTask eşleşen map, bindve hata yardımcıları sunar; bkz. Zaman uyumsuz ve görev işlevleri. Dallar veya birkaç bağımlı değer için bir computation expression kullanın.
ValueTask yardımcıları, Core'un net10.0 veya netstandard2.1 derlemesini ve tek seferlik tüketimi gerektirir.
@bartelink'e async/task API katkıları için teşekkürler.
Zaman uyumsuz hata raporlamasından sonra yeniden fırlatma
İşlem günlüğü, çağıranın yakaladıklarını değiştirmeden veya hatanın başladığı yeri gizlemeden bilgi eklemelidir. Hesaplama-ifade işleyicileri artık logger’ı bekledikten sonra bile reraise () kullanabilir:
Note
Hesaplama ifadesinde yeniden fırlatma, F# 11.2 özelliğidir. .NET 11.0.100 SDK'sında <LangVersion>preview</LangVersion> etkinleştirin.
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 ()
}
Başarıyla oturum açıldıktan sonra, aynı özel durum ve özgün throw-site bilgileri yayılır. Bir logger hatası orijinalinin yerini alabilir. Bu, çalışma zamanında eşzamansızlık olmadan eşzamansız gözlemlenebilirlik gereksinimini karşılar. Bkz. Hesaplama ifadesinden yeniden oluşturma.
Bu destek için @xperiandri'ye teşekkür ederiz.
FSharp.Core modern .NET üzerinde derlenebilir
Modern API’leri eski hedef platformlarını bırakmadan kullanmak için FSharp.Core, netstandard2.1 ile birlikte netstandard2.0 ve net10.0 ekler. NuGet uyumlu derlemeyi seçer. Güncelleştirilmiş araç paketlemesi, derlenmiş projelerde olduğu gibi F# Interactive'te de görev tabanlı zaman uyumsuz elden çıkarmaya olanak tanır. Bkz. FSharp.Core hedef çerçeveleri.
@T-Gro modern Core hedefleme ve SDK aracı paketlemesi için teşekkürler.
Oluşturucu yazarları için çalışma zamanı eşzamansızlığı
Oluşturucu yazarları, derleyici tarafından oluşturulan durum makinelerini kullanmak yerine çalışma zamanının işaretli yöntemleri askıya almasına ve sürdürmesine izin verebilir. Kitaplık tarafından tanımlanan deneysel bir builder, bu mekanizmayı bir hesaplama ifadesi olarak sunar:
let readManifest (path: string) =
runtimeTask {
let! text = System.IO.File.ReadAllTextAsync path
return text.Length
}
Note
Bu deneysel oluşturucu, satır içi uygulamasının tanımlanıp genişletildiği bir F# 11.2 özelliğini kullanır; .NET 11.0.100 SDK’da önizlemeyi etkinleştirin. Ayrıca Core 11'in net10.0 derleme ve başvuruları ile runtime-async desteğine sahip bir çalışma zamanı gerektirir. Burada doğrulanan çalışma zamanı/referans bileşimi .NET 11 RC1'dir. Yalnızca .NET 10'u hedeflemek yeterli değildir. Bkz. Çalışma zamanı eşzamansız deneyleri.
FSharp.Core bu örneği genel amaçlı bir oluşturucu olarak sunmaz. Normal task ve async kod otomatik olarak buna geçiş yapmaz ve zaten derlenmiş sıradan bir görev döndüren API'nin çağıranlarının doğal olarak preview özelliğine ihtiyacı yoktur.
@majocha'ya runtime async için teşekkürler.
Yerel AOT uyumlu metin ve iki boyutlu diziler
Native AOT'yi desteklemek için F# 11, yansıma tabanlı biçimlendirme ve dinamik bellek ayırma gereksinimlerini yaygın olarak kullanılan metin ve dizi işlemlerinden ortadan kaldırır.
Gereksiz bir biçim katmanı olmadan değer yazdırma ve dizeler oluşturma
Zaten bir string'iniz varsa, yalnızca yazmak için bir "%s" biçimine ihtiyacınız yoktur. Yeni Core işlevleri print ve printn F# string dönüştürmesi aracılığıyla değerleri kabul eder; printn yeni bir satır ekler:
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
String interpolation'da doğrudan dönüştürme ve String.Concat, daha fazla durumda kullanılır.
{total:F2} gibi .NET biçimindeki yer tutucular değişmez biçimlendirme kullanır ve değeri kutular; %A ile duyarlık belirten printf biçimleri ise yine de printf biçimlendirmesi gerektirebilir. Yerelleştirilmiş çıkış için açık bir yerel ayar seçin.
--reflectionfree ile, kayıtlar ve birleşimler için de oluşturulan ToString çıktısı sağlanır. Kültür örnekleri ve desteklenen yollar için bkz. Interpolation ve Native AOT.
Yazdırma işlevleri için @bbatsov'a ve enterpolasyon uygulaması için @charlesroddie'ye teşekkürler.
Sıradan sıfır tabanlı ızgara işlemlerini koru
Sıfır tabanlı bir ızgara, yalnızca dinamik kod tahsisi yolundan kaçınmak için Array2D yerine başka bir modül gerektirmemelidir. Güncelleştirilmiş Çekirdek uygulamaları tanıdık başlatmayı ve dönüştürmeyi destekler:
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 ve rebase Core derlemelerinde sıfır tabanlı ayırma yolunu kullanır. Sınırları koruyan map, mapi ve copy, net10.0 derlemesinde daha yeni bir .NET bellek ayırma API'sini kullanabilir; .NET Standard derlemeleri ise yedek çözümünü kullanmaya devam eder. Sıfır tabanlı olmayan diziler kullanım dışı değildir, ancak yerleşik ayırma kısıtlamaları sürer.
Ayırma yolları ve kalan kısıtlamalar için bkz. İki boyutlu diziler ve Native AOT. Uygulamanın yayımlama tanılamasının tamamını denetleyin.
Array2D geliştirmeleri için @T-Gro'ya teşekkürler.
Bellekte daha az tutulan veri ve daha az tekrarlanan işlem
F# 11 yinelenen derleyici analizini ve bazı uygulama bellek ayırmalarını azaltır. Bunlar farklı iş yüklerini etkiler.
Başvurulan kitaplıkları projeler arasında paylaşın
Paylaşılan ikili bağımlılıkların yinelenen kopyalarını önlemek için dil hizmeti uygun içeri aktarılan kitaplık grafiklerini projeler arasında paylaşabilir.
Uygulayan PR'nin tutulan bellek denemesinde, on projeli ReSharper.FSharp çözümü, paylaşım etkinken 1.547,2 MB'tan 1.002,2 MB'a düştü. Bu, genel bir F# 10-11 azaltması değil, bu iş yükü için açık/kapalı ölçümüdür. Paylaşılan ikili referanslar yerine proje referanslarının hakim olduğu çözümler çok daha küçük kazançlar görebilir.
Meta veri okuma ve satır içi özelleştirme, ayrı bir ölçüm olan geçici ayırmaları da azaltır. Bkz. Kapsam ve denetimler için Araçlandırma performansı.
Paylaşılan kitaplık içe aktarmaları için @auduchinok'a teşekkürler.
Bağımsız işleri varsayılan olarak paralel derle
Paralel derleme artık varsayılan olarak etkindir ve deterministik çıktı ile kaynak sırası kuralları korunmaktadır. Aşırı yükleme önbelleklemesi ve korumalı desen iyileştirmeleri, diğer yinelenen işleri önler. Visual Studio/FCS ayrıca değişmemiş belge analizini azaltır ve eşzamanlı denetimleri sınırlar; bkz. Araç performansı.
Geri çağırma ve boş sonuç için bellek ayırma ek yükünden kaçının
Seçili List ve Array işlevleri artık geri çağrıları satır içine alır. Kendi satır içi yardımcılarınız için, OptimizeClosureIfNotInlined opak bir curried geri çağırmayı bir kez uyarlar:
let inline foldItems
([<InlineIfLambda; OptimizeClosureIfNotInlined>] folder)
state
(items: 'T[]) =
let mutable total = state
for item in items do
total <- folder total item
total
Diğer tahsisler kalabilir. Gereksinimler için bkz. Optimize curried callbacks.
Boş sonuçlar, başarılı çalışmanın bir diğer yaygın durumudur. FSharpLint’in esin kaynağı olan iş yükü, hiç uyarı bulmayan kuralları tekrar tekrar birleştirdi. Çekirdek artık paylaşılan boş dizileri daha fazla işlemde yeniden kullanır:
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
Değişiklik, işlem hattındaki her ayırmayı değil yedekli boş dizi nesnelerini kaldırır. Ayrı boş sonuçların farklı referans kimliklerine sahip olacağına güvenmeyin.
@T-Gro Satır içi koleksiyon geri çağırmaları ve paylaşılan boş diziler için teşekkür ederiz.
Daha hassas API çağrıları ve günlük kolaylıklar
Oluşturulan parametre sırası değişebildiğinde adları zorunlu kılın
Oluşturulan API'leri sessiz parametre sırası değişikliklerine karşı korumak için yazar adlandırılmış bağımsız değişkenler gerektirebilir:
Note
Enforcement, F# 11.2 özelliğidir; .NET 11.0.100 SDK'sında önizlemeyi etkinleştirin. Kullanılabilir bir System.Diagnostics.CodeAnalysis.RequireNamedArgumentsAttribute tanım da gereklidir.
Tam örnek, bunu içermeyen başvurular için bir uyumluluk tanımı sağlar.
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.
Bildirimin yeniden sıralanması adlandırılmış 0.75Mçağrının sonucunu korur; konumsal bir çağrı reddedilir.
Oluşturulan API kullanım örneği için sağlayıcının ek açıklamayı yayması gerekir.
Zaten sarmalanmış bir jenerik bağımsız değişkeni tanıma
Mevcut bir görevi düz sonuç değeri olarak sarmalamamak için, yeni bir son çare aşırı yükleme kuralı, çıplak Task<'T> yerine 'T öğesini tercih eder:
Note
En somut eşitlik bozucu ve aşırı yük önceliği davranışı, F# 11.2 özellikleridir; .NET 11.0.100 SDK'sında önizlemeyi etkinleştirin.
open System.Threading.Tasks
let pending = Task.FromResult 42
let wrapped = ValueTask<_>(pending)
let answer: int = wrapped.Result
// ValueTask<int>, not ValueTask<Task<int>>
Sonuç ValueTask<Task<int>>, ValueTask<int> değil.
Aşırı yükleme seçimi bölümünde kuralın sınırlarına bakın.
Eski giriş noktasını kaldırmadan yeni bir aşırı yüklemeyi tercih edin
Kitaplık, çağıranın kaynak konumunu içeren bir overload imzası eklerken mevcut ikili dosyalar için eski bir tanılama yöntemini tutabilir.
OverloadResolutionPriorityAttribute bu tercihi yeni derlenen çağıran kodlar için açık hale getirir:
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.
Değişmeyen çağrı, satır algılayan aşırı yüklenmiş yöntemi seçer. Kapsam ve uyumluluk kuralları için bkz. Aşırı yükleme seçimi .
.NET'in koşullu null atanabilirlik vaatlerini kullanın
Dosya yolunuz null değilse, bir Path API'sinin null atanabilir sonucu, kendi sözleşmesinin zaten dışladığı bir denetime zorlamamalıdır. F# 11, var olan .NET NotNullIfNotNull güvencesini kullanır: null olmayan adlandırılmış bir giriş, null olmayan bir sonuç anlamına gelir.
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
'yi etkinleştirin <Nullable>enable</Nullable>. Nullable girişler yine de nullable işleme gerektirir; bkz. Koşullu dönüş sözleşmeleri. Kısıtlanmamış C# T? API'leri için ayrı Unchecked.withNull yardımcıyı kullanın.
Koşullu null atanabilirlik desteği için @kerams'e teşekkürler.
Daha küçük metin iyileştirmeleri
Bir kayıt türünü .NET oluşturucu söz dizimiyle oluşturmak için F# 11.2 kayıt oluşturucularını kullanın:
type Person = { Name: string; Age: int }
let person = Person(Name = "Ada", Age = 36)
Adlandırılmış bağımsız değişkenler alan sırasına bağımlılığı ortadan kaldırır. @charlesroddie'ye bu özellik için teşekkürler.
Koşullu kaynak için #elif, iç içe #if gruplarını önler:
#if EU_WAREHOUSE
let dispatchTimeZone = "Europe/Paris"
#elif US_WAREHOUSE
let dispatchTimeZone = "America/New_York"
#else
let dispatchTimeZone = "UTC"
#endif
System.Console.WriteLine(dispatchTimeZone)
İlk eşleşen dal kazanır. Örnek proje EU_WAREHOUSE tanımlar ve Europe/Paris yazdırır; iki sembolden hiçbiri tanımlı değilken çıktı UTC olur.
İlgili araçlar ve birlikte çalışma durumları için:
- Etkileşimli araç zincirinizi tanımlamak için
#versionkullanın. - Kaynağı harici bir ana bilgisayarla paylaşmak için F#,
#:konak yönergesi satırlarını bunları paket veya derleme yönergeleri olarak yorumlamadan kabul eder. - Yedekli arabirim bildirimlerini önlemek için türetilmiş arabirimin varsayılan uygulamasını kullanın.
- Normal bir closure içindeki devralınan durumu okumak için, protected taban alanları için sunulan yeni desteği kullanın.
Yükseltmeden önce
Yükseltme yaparken bu önemli değişiklikleri göz önünde bulundurun:
| Etkilenen kod | Action |
|---|---|
Dosya içeren .fsi kitaplıklar |
Zorunlu sözleşme özniteliklerini imzalara kopyalama; eksiklikler artık FS3888 hatalarıdır. |
| Uzantı tabanlı satır içi kitaplıklar | Çıkarsanan imzaları ve üretici/tüketici gereksinimlerini gözden geçirin. F# 11.2 çıkarımı daha genel kısıtlamaları koruyabilir. |
| Örnek yöntem temsilcileri | Doğrudan oluşturmadan önce, artık null alıcı hataları oluştuğundan alıcıları doğrulayın. |
| Yerelleştirilmiş enterpole edilmiş çıktı | .NET biçimi yer tutucuları değişmez kültür kullanır. Yerelleştirilmiş çıktı amaçlandığında belirli bir kültür seçin. |
Son hali olan özel oluşturucular do! |
Bağlama ve birim tamamlamayı sağlar; final do! artık final yönlendiren üyeleri seçmez. |
Tamamlanmamış let! |
Aşağıdaki hesaplama gövdesini ekleyin; tamamlanmamış bir binding artık daha doğrudan bir tanı iletisi verir. |
| Eski dil ayarları | Desteklenen numaralandırılmış modlar F# 8'de başlar; katı olmayan girinti modu kaldırıldı. Bkz. Dil sürümü ve girintileme. |
| Enum bit düzeyinde işlemleri | Temel türü tamsayı olan enum'ları kullanın; geçersiz temel türler reddedilir. |