ByRef’ler
F# alt düzey programlama alanıyla ilgilenen iki önemli özellik alanına sahiptir:
byref
//inref
outref
Yönetilen işaretçiler olan türler. Çalışma zamanında geçersiz olan bir programı derleyemezsiniz diye kullanım kısıtlamaları vardır.- benzer
byref
semantiklere ve ile aynı derleme zamanı kısıtlamalarınabyref<'T>
sahip bir yapı olan bir -like yapısı. Örneklerden biri de şeklindedir 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
üç biçimi byref
vardır:
inref<'T>
, temel alınan değeri okumak için yönetilen bir işaretçi.outref<'T>
, temel alınan değere yazmak için yönetilen bir işaretçi.byref<'T>
, temel alınan değeri okumak ve yazmak için yönetilen bir işaretçi.
beklendiği byref<'T>
yerde geçirilebilir inref<'T>
. Benzer şekilde, bir byref<'T>
beklendiği yerde outref<'T>
geçirilebilir.
Byrefs'i kullanma
kullanmak inref<'T>
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'
veya byref<'T>
kullanarak outref<'T>
işaretçiye yazmak için, işaretçiyi yakalayabileceğiniz mutable
değeri de yapmalısınız.
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 yerine kullanmayı outref<'T>
byref<'T>
göz önünde bulundurun.
Inref semantiği
Aşağıdaki kodu inceleyin:
let f (x: inref<SomeStruct>) = x.SomeField
Bu, anlam olarak şu anlama gelir:
- İşaretçinin
x
tutucusu yalnızca değeri okumak için kullanabilir. - İç
SomeStruct
içe yerleştirilmiş alanlarastruct
alınan tüm işaretçilere türüinref<_>
verilir.
Aşağıdakiler de geçerlidir:
- Diğer iş parçacıklarının veya diğer adların üzerinde
x
yazma erişimi olmamasının bir etkisi yoktur. - bir olma özelliğiyle
x
sabit olan birinref
imaSomeStruct
yoktur.
Ancak sabit olan F# değer türleri için işaretçi this
bir inref
olarak çıkarılır.
Bu kuralların tümü birlikte bir inref
işaretçinin sahibinin işaret edilen belleğin hemen içeriğini değiştiremediğini gösterir.
Outref semantiği
amacı outref<'T>
, işaretçinin yalnızca öğesine yazılması gerektiğini belirtmektir. Beklenmedik şekilde, outref<'T>
adına rağmen temel alınan değerin okunmasını sağlar. Bu, uyumluluk amaçlıdır.
Tek bir fark dışında, diğer bir deyişle, outref<'T>
değerinden byref<'T>
farklı değildir: parametreleri olan yöntemler, bir parametreyle outref<'T>
[<Out>]
bir yöntemi çağırırken olduğu gibi örtük olarak bir tanımlama grubu dönüş türüne oluşturulur.
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# ve anahtar sözcüklerinin in ref
out ref
yanı sıra ref
dönüşleri de destekler. Aşağıdaki tabloda, F# öğesinin C# tarafından nelerin yaydığı gösterilmektedir:
C# yapısı | F# çıkarımları |
---|---|
ref dönüş değeri |
outref<'T> |
ref readonly dönüş değeri |
inref<'T> |
in ref Parametre |
inref<'T> |
out ref Parametre |
outref<'T> |
Aşağıdaki tabloda F# tarafından nelerin yaydığı gösterilmektedir:
F# yapısı | Yayılan yapı |
---|---|
inref<'T> bağımsız değişkeni |
[In] bağımsız değişkende özniteliği |
inref<'T> Dönüş |
modreq değerde özniteliği |
inref<'T> soyut yuvada veya uygulamada |
modreq bağımsız değişkende veya dönüşte |
outref<'T> bağımsız değişkeni |
[Out] bağımsız değişkende özniteliği |
Tür çıkarımı ve aşırı yükleme kuralları
inref<'T>
Aşağıdaki durumlarda F# derleyicisi tarafından bir tür çıkarılır:
- Özniteliği olan bir
IsReadOnly
.NET parametresi veya dönüş türü. this
Değiştirilebilir alanları olmayan bir yapı türü üzerindeki işaretçi.- Başka
inref<_>
bir işaretçiden türetilen bellek konumunun adresi.
örtük bir adresi inref
alındığında, türünde bağımsız değişken içeren bir aşırı yükleme, türü SomeType
bağımsız değişkeni inref<SomeType>
olan bir 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, aşırı System.DateTime
yüklemeler yerine aşırı inref<System.DateTime>
yüklemeler çözülür.
Byref benzeri yapılar
Üçlüye byref
//inref
outref
ek olarak, benzer semantiklere byref
bağlı kalabilecek kendi yapılarınızı tanımlayabilirsiniz. Bu işlem şu öznitelikle IsByRefLikeAttribute 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
anlamına Struct
gelmez. Her ikisi de türünde bulunmalıdır.
F# dilindeki "byref
benzer" yapı, yığına bağlı bir değer türüdür. Yönetilen yığında hiçbir zaman ayrılmaz. byref
Benzer bir yapı, yüksek performanslı programlama için kullanışlıdır, yaşam süresi ve yakalama olmayanlar hakkında güçlü denetimler kümesiyle zorunlu kılını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ı (
async
yöntemler veya lambda ifadeleri) tarafından yakalanamaz. - Genel parametre olarak kullanılamazlar.
Bu son nokta, giriş türlerini parametreleştiren genel bir işlev olduğu gibi |>
F# işlem hattı stili programlama için de çok önemlidir. Bu kısıtlama, satır içi olduğundan ve gövdesinde satır içi olmayan genel işlevlere çağrı yapmadığından 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. -dönüş yöntemi kullanıldığında byref
, değer örtük olarak başvurulmaz. Ö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 &value
döndürmek için 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 zincirleme çağrıdan bir başvuru geçirme gibi örtük başvurudan kaçınmak için kullanın &x
(burada x
değerdir).
Ayrıca doğrudan bir iadeye byref
de atayabilirsiniz. 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
Bu çıktı.
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
let
İlişkili bir değer, başvurusunun tanımlandığı kapsamı aşmasına neden olamaz. Ö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.