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# alt düzey programlama alanıyla ilgilenen iki önemli özellik alanına sahiptir:
- yönetilen işaretçiler olan
byref/inref/outreftürleri. Çalışma zamanında geçersiz olan bir programı derleyemezsiniz diye kullanım kısıtlamaları vardır. - benzer semantiklere ve
byrefile aynı derleme zamanı kısıtlamalarına sahipbyref<'T>. Örnek olarak Span<T>.
Sözdizimi
// Byref types as parameters
let f (x: byref<'T>) = ()
let g (x: inref<'T>) = ()
let h (x: outref<'T>) = ()
// Calling a function with a byref parameter
let mutable x = 3
f &x
// Declaring a byref-like struct
open System.Runtime.CompilerServices
[<Struct; IsByRefLike>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
Byref, inref ve outref
üç byrefbiçimi vardır:
-
inref<'T>, temel değeri okumak için yönetilen bir işaretçidir. -
outref<'T>, temel alınan değere yazmak için bir yönetilen işaretçidir. -
byref<'T>, altında yatan değeri okumak ve yazmak için yönetilen bir işaretçidir.
byref<'T>'nın yerine inref<'T>'in beklendiği yerde geçirilebilir. Benzer şekilde, byref<'T> beklendiği yerde bir outref<'T> geçirilebilir.
Byrefs'i kullanma
inref<'T>kullanmak için, &ile bir işaretçi değeri almanız gerekir:
open System
let f (dt: inref<DateTime>) =
printfn $"Now: %O{dt}"
let usage =
let dt = DateTime.Now
f &dt // Pass a pointer to 'dt'
Bir outref<'T> veya byref<'T>kullanarak işaretçiye yazmak için, aynı zamanda elde ettiğiniz değeri mutableiçin bir işaretçi haline getirmeniz gerekmektedir.
open System
let f (dt: byref<DateTime>) =
printfn $"Now: %O{dt}"
dt <- DateTime.Now
// Make 'dt' mutable
let mutable dt = DateTime.Now
// Now you can pass the pointer to 'dt'
f &dt
İşaretçiyi okumak yerine yalnızca yazıyorsanız, outref<'T>yerine byref<'T> kullanmayı düşünün.
Inref semantiği
Aşağıdaki kodu göz önünde bulundurun:
let f (x: inref<SomeStruct>) = x.SomeField
Bu, anlam olarak şu anlama gelir:
-
xişaretçisinin tutucusu yalnızca değeri okumak için kullanabilir. -
structiç içe yerleştirilmişSomeStructalanlara alınan tüm işaretçilereinref<_>türü verilir.
Aşağıdakiler de geçerlidir:
- Diğer iş parçacıklarının veya diğer adların
xyazma erişimine sahip olmadığını gösteren bir sonuç yoktur. -
SomeStruct'ın değiştirilmez olduğu söylenemez çünküxbirinref'dir.
Ancak, sabit olan F# değer türleri için, this işaretçisi inrefolarak çıkarılır.
Bu kuralların tümü birlikte, bir inref işaretçisinin sahibinin işaret edilen belleğin hemen içeriğini değiştiremeyeceği anlamına gelir.
Outref semantiği
outref<'T>'ın amacı, işaretçinin yalnızca üzerine yazılabileceğini belirtmektir. Beklenmedik şekilde, outref<'T> adına rağmen temel alınan değerin okunmasına izin verir. Bu, uyumluluk amaçlıdır.
Semantik olarak, outref<'T>'un byref<'T>'den tek farkı şudur: outref<'T> parametreleri içeren yöntemler, tıpkı [<Out>] parametresine sahip bir yöntemi çağırırken olduğu gibi, örtük olarak tanımlama grubu dönüş türüne dönüştürülür.
type C =
static member M1(x, y: _ outref) =
y <- x
true
match C.M1 1 with
| true, 1 -> printfn "Expected" // Fine with outref, error with byref
| _ -> printfn "Never matched"
C# ile birlikte çalışma
C# in ref ve out ref anahtar sözcüklerinin yanı sıra ref dönüşlerini de destekler. Aşağıdaki tabloda, C# dilinin ürettiklerini F# dilinin nasıl yorumladığı gösterilmektedir.
| C# dil yapısı | F# çıkarım yapar |
|---|---|
ref dönüş değeri |
outref<'T> |
ref readonly dönüş değeri |
inref<'T> |
in ref parametresi |
inref<'T> |
out ref parametresi |
outref<'T> |
Aşağıdaki tablo, F#'ın ürettiklerini gösteriyor.
| F# yapısı | Yayılan yapılandırma |
|---|---|
inref<'T> bağımsız değişkeni |
Argümandaki [In] özniteliği |
inref<'T> iade |
Değer üzerinde modreq özniteliği |
Soyut yuva veya uygulamada inref<'T> |
modreq bağımsız değişken veya dönüş üzerinde |
outref<'T> bağımsız değişkeni |
Argümandaki [Out] özniteliği |
Tür çıkarımı ve aşırı yükleme kuralları
Aşağıdaki durumlarda F# derleyicisi tarafından bir inref<'T> türü çıkarılır:
-
IsReadOnlyözniteliğine sahip bir .NET parametresi veya dönüş türü. - Değiştirilebilir alanları olmayan bir yapı türü üzerindeki
thisişaretçisi. - Başka bir
inref<_>işaretçisinden türetilen bellek konumunun adresi.
Bir inref adresi örtük olarak alındığında, SomeType türünde bir bağımsız değişkene sahip aşırı yükleme, inref<SomeType>türünde bir bağımsız değişkene sahip aşırı yüklemeye tercih edilir. Örneğin:
type C() =
static member M(x: System.DateTime) = x.AddDays(1.0)
static member M(x: inref<System.DateTime>) = x.AddDays(2.0)
static member M2(x: System.DateTime, y: int) = x.AddDays(1.0)
static member M2(x: inref<System.DateTime>, y: int) = x.AddDays(2.0)
let res = System.DateTime.Now
let v = C.M(res)
let v2 = C.M2(res, 4)
Her iki durumda da System.DateTime alan aşırı yüklemeler, inref<System.DateTime>alan aşırı yüklemeler yerine çözülür.
Byref benzeri yapılar
byref
/
inref
/
outref trio'ya ek olarak, byrefbenzeri semantiklere bağlı kalabilecek kendi yapılarınızı tanımlayabilirsiniz. Bu işlem IsByRefLikeAttribute özniteliğiyle yapılır:
open System
open System.Runtime.CompilerServices
[<IsByRefLike; Struct>]
type S(count1: Span<int>, count2: Span<int>) =
member x.Count1 = count1
member x.Count2 = count2
IsByRefLike
Structanlamına gelmez. Her ikisi de tipinde bulunmalıdır.
F# dilinde "byref-like" yapısı, yığına bağlı bir değer türüdür. Yönetilen yığında hiçbir zaman tahsis edilmez.
byrefgibi bir yapı, ömrü ve yakalanmama konusunda güçlü denetimlerle desteklendiğinden yüksek performanslı programlamada faydalıdır. Kurallar şunlardır:
- İşlev parametreleri, yöntem parametreleri, yerel değişkenler, yöntem dönüşleri olarak kullanılabilirler.
- Statik veya bir sınıfın veya normal yapının örnek üyeleri olamazlar.
- Bunlar herhangi bir kapatma yapısı (
asyncyöntemleri veya lambda ifadeleri) tarafından yakalanamaz. - Genel parametre olarak kullanılamazlar.
- F# 9'dan itibaren, genel parametre C# dilinde ref struct sınırlaması kaldırarak tanımlanırsa bu kısıtlama gevşetilir. F#, byref benzeri tiplerle tip ve metotlarda bu tür genel tiplerin örneğini oluşturabilir. Birkaç örnek olarak, bu BCL temsilci türlerini (
Action<>,Func<>), arabirimleri (IEnumerable<>,IComparable<>) ve kullanıcı tarafından sağlanan bir biriktirici işleviyle (String.string Create<TState>(int length, TState state, SpanAction<char, TState> action)) genel bağımsız değişkenleri etkiler. - F# dilinde byref benzeri türleri destekleyen genel kod yazmak mümkün değildir.
- F# 9'dan itibaren, genel parametre C# dilinde ref struct sınırlaması kaldırarak tanımlanırsa bu kısıtlama gevşetilir. F#, byref benzeri tiplerle tip ve metotlarda bu tür genel tiplerin örneğini oluşturabilir. Birkaç örnek olarak, bu BCL temsilci türlerini (
|> giriş türlerini parametreleştiren genel bir işlev olduğundan, bu son nokta F# işlem hattı stili programlama için çok önemlidir. Bu kısıtlama, satır içi olduğu ve gövdesinde satır içi olmayan genel fonksiyonlara çağrıda bulunmadığı için gelecekte |> için gevşetilebilir.
Bu kurallar kullanımı güçlü bir şekilde kısıtlasa da, yüksek performanslı bilgi işlem sözünü güvenli bir şekilde yerine getirmek için bunu yapar.
Byref döndürür
F# işlevlerinden veya üyelerinden Byref dönüşleri üretilebilir ve kullanılabilir.
byref-dönüş yöntemi kullanıldığında, değer örtük olarak işlenir. Örneğin:
let squareAndPrint (data : byref<int>) =
let squared = data*data // data is implicitly dereferenced
printfn $"%d{squared}"
Bir değer byref döndürmek için, değeri içeren değişkenin geçerli kapsamdan daha uzun yaşaması gerekir.
Ayrıca, byref döndürmek için &value kullanın (burada değer, geçerli kapsamdan daha uzun süre yaşayan bir değişkendir).
let mutable sum = 0
let safeSum (bytes: Span<byte>) =
for i in 0 .. bytes.Length - 1 do
sum <- sum + int bytes[i]
&sum // sum lives longer than the scope of this function.
Birden çok zincirli çağrıdan referans geçirme gibi örtük dereferansı önlemek için &x kullanın (burada x değerdir).
Ayrıca doğrudan bir dönüş etiketi byrefatayabilirsiniz. Aşağıdaki (son derece zorunlu) programı göz önünde bulundurun:
type C() =
let mutable nums = [| 1; 3; 7; 15; 31; 63; 127; 255; 511; 1023 |]
override _.ToString() = String.Join(' ', nums)
member _.FindLargestSmallerThan(target: int) =
let mutable ctr = nums.Length - 1
while ctr > 0 && nums[ctr] >= target do ctr <- ctr - 1
if ctr > 0 then &nums[ctr] else &nums[0]
[<EntryPoint>]
let main argv =
let c = C()
printfn $"Original sequence: %O{c}"
let v = &c.FindLargestSmallerThan 16
v <- v*2 // Directly assign to the byref return
printfn $"New sequence: %O{c}"
0 // return an integer exit code
Çıkış şu şekildedir:
Original sequence: 1 3 7 15 31 63 127 255 511 1023
New sequence: 1 3 7 30 31 63 127 255 511 1023
Byrefs için kapsam belirleme
letbağlı bir değerin, referansının tanımlandığı kapsamı aşması mümkün değildir. Örneğin, aşağıdakilere izin verilmiyor:
let test2 () =
let x = 12
&x // Error: 'x' exceeds its defined scope!
let test () =
let x =
let y = 1
&y // Error: `y` exceeds its defined scope!
()
Bu, iyileştirmelerle derleyip derlemediğinize bağlı olarak farklı sonuçlar almanızı önler.