F #: değişebilir vs. ref


83

İlk olarak, bu sorunun bir kopya olma olasılığını kabul ediyorum; sadece bana bildirin.

Değişkenliğin istendiği durumlar için genel "en iyi uygulamanın" ne olduğunu merak ediyorum. F # bunun için iki kolaylık sunuyor let mutablegibi görünüyor: "çoğu" dilde değişkenler gibi çalışıyor gibi görünen bağlama ve kullanmak için açık başvuruyu refgerektiren referans hücre ( işlevle oluşturulmuş ).

Orada tek tek ya da diğer içine "zorla" durumlarda bir çift: .NET birlikte çalışma ile değişken kullanmak eğilimindedir <-ve iş akışı hesaplamalarda biri kullanmalısınız refile :=. Yani bu durumlar oldukça net, ancak bu senaryoların dışında kendi değişken değişkenlerimi oluştururken ne yapacağımı merak ediyorum. Bir stilin diğerine göre avantajı nedir? (Belki uygulama hakkında daha fazla bilgi sahibi olmak yardımcı olabilir.)

Teşekkürler!



4
F # sürüm 4'te, bir ref'e ihtiyaç duyduğunuzda mutable'ın kullanılabileceğini unutmayın. blogs.msdn.com/b/fsharpteam/archive/2014/11/12/…
James Moore

Yanıtlar:


134

Sadece gradbot'un söylediklerini destekleyebilirim - mutasyona ihtiyacım olduğunda tercih ederim let mutable.

İki refhücre arasındaki uygulama ve farklılıklar ile ilgili olarak , esasen değiştirilebilir bir kayıt alanı içeren çok basit bir kayıt tarafından gerçekleştirilir. Bunları kendiniz kolayca yazabilirsiniz:

type ref<'T> =  // '
  { mutable value : 'T } // '

// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }

İki yaklaşım arasındaki dikkate değer bir fark let mutable, değişken değeri yığın üzerinde depolarken (C # 'da değiştirilebilir bir değişken olarak) ref, değişken değeri bir yığın tahsisli kaydın bir alanında depolar. Bunun performans üzerinde bir etkisi olabilir, ancak elimde rakam yok ...

Bu sayede, kullanılan değişken değerlere reftakma ad verilebilir - bu, aynı değiştirilebilir değere başvuran iki değer oluşturabileceğiniz anlamına gelir:

let a = ref 5  // allocates a new record on the heap
let b = a      // b references the same record
b := 10        // modifies the value of 'a' as well!

let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10           // modifies the value of 'b' only!

2
Sadece bir hatırlatma: yığında veya yığında olmak bir uygulama ayrıntısıdır ve soruyla tam olarak alakalı değildir (ancak yine de mükemmel bir cevap)
Bruno Brant

5
En iyi uygulamanın ne olduğuna karar verirken bir şeyin yığın tahsisi ve toplama ek yüküne maruz kalıp kalmadığını bilmenin son derece alakalı olduğunu iddia ediyorum.
jackmott

@jackmott Eric Lippert tarafından yazılan The Stack Is An Implementation Detail
jaromey

5
@jaromey evet, bu noktada Eric'e temelde tamamen katılmadığımı anlıyorum. 'En iyi uygulamanın' ne olduğunu düşünürken performans değerlendirmelerini bir kenara bırakamazsınız. Genellikle performansın önemli olmadığı iddia edilir, ancak bu kadar çok yazılım, bin uygulama ayrıntısından ölüm nedeniyle yavaşlar.
jackmott

18

İlgili Soru: "Yerel değişken değerlerin bir kapatma tarafından yakalanamayacağından bahsettiniz, bu nedenle bunun yerine ref kullanmanız gerekir. Bunun nedeni, kapanışta yakalanan değişken değerlerin yığın üzerinde tahsis edilmesi gerektiğidir (çünkü kapama, yığın). " dan F # ref-değişken değişkenler nesne alanları vs

let mutableReferans hücrelere göre tercih edildiğini düşünüyorum . Ben şahsen referans hücreleri sadece gerektiğinde kullanıyorum.

Yazdığım çoğu kod, özyineleme ve kuyruk çağrıları sayesinde değişken değişkenler kullanmıyor. Bir grup değiştirilebilir verim varsa, bir kayıt kullanırım. Nesneler let mutableiçin özel değişkenler yapmak için kullanıyorum . Kapanışlar için, genellikle olaylar için gerçekten referans hücreleri kullanıyorum.


9

Bu MSDN Blog makalesinde Değiştirilebilir değerlerin basitleştirilmiş kullanımı bölümünde açıklandığı gibi, lambdalar için artık başvuru hücrelerine ihtiyacınız yoktur. Yani genel olarak artık onlara ihtiyacınız yok.


4

Brian'ın yazdığı bu makale bir cevap sağlayabilir.

Değişkenlerin kullanımı kolay ve etkilidir (sarma yoktur), ancak lambdalarda yakalanamaz. Referans hücreler olabilir yakalanan, ancak ayrıntılı ve daha az verimlidir edilmesi (? - değil emin bu).


"(...) ve daha az verimli" - muhtemelen, bir sarmalayıcı türü daha fazla bellek alır.
JMCF125

2
F # 4.0 mutable çoğu durumda yakalanabildiğinden ve ref ihtiyacı artık çok daha az olduğundan, bu değişti.
Abel

3

Vikikitap'ta Değişken Veriler bölümüne göz atmak isteyebilirsiniz .

Kolaylık sağlamak için işte bazı ilgili alıntılar:

Mutable anahtar sözcüğü, değiştirilebilir kayıtlar oluşturmak için kayıt türlerinde sıklıkla kullanılır.

Değişken değişkenler bir şekilde sınırlıdır: değişkenler, tanımlandıkları fonksiyonun kapsamı dışında erişilemez. Spesifik olarak, bu, başka bir fonksiyonun bir alt fonksiyonundaki bir değişkene atıf yapmanın mümkün olmadığı anlamına gelir.

Referans hücreleri, değişkenlerin bazı sınırlamalarını aşar. Aslında, başvuru hücreleri, bir kayıt türünde değiştirilebilir bir alanı saran çok basit veri türüdür.

Başvuru hücreleri yığın üzerinde tahsis edildiğinden, birden çok işlev arasında paylaşılabilirler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.