Po pierwsze, przyznaję, że to pytanie może być powtórzeniem; po prostu daj mi znać.
Jestem ciekaw, jaka jest ogólna „najlepsza praktyka” w sytuacjach, gdy pożądana jest zmienność. Wydaje się, że F # oferuje do tego dwie możliwości: let mutable
powiązanie, które wydaje się działać jak zmienne w „większości” języków, oraz komórkę odniesienia (utworzoną za pomocą ref
funkcji), która wymaga jawnego wyłuskiwania.
Istnieje kilka przypadków, w których jedna jest „zmuszony” do jednej lub drugiej: NET współdziałanie ma tendencję do korzystania z zmienny <-
, aw workflow obliczeń należy używać ref
z :=
. Więc te przypadki są dość jasne, ale jestem ciekawy, co zrobić, tworząc własne zmienne zmienne poza tymi scenariuszami. Jaką przewagę ma jeden styl nad drugim? (Być może pomocny byłby dalszy wgląd w implementację).
Dzięki!
Odpowiedzi:
Mogę tylko poprzeć to, co powiedział gradbot - kiedy potrzebuję mutacji, wolę
let mutable
.Odnośnie implementacji i różnic między tymi dwiema
ref
komórkami - są zasadniczo implementowane przez bardzo prosty rekord, który zawiera zmienne pole rekordu. Możesz je łatwo napisać samodzielnie: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 }
Istotną różnicą między tymi dwoma podejściami jest to, że
let mutable
przechowuje zmienną wartość na stosie (jako zmienną modyfikowalną w C #), podczas gdyref
przechowuje zmienną wartość w polu rekordu przydzielonego na sterty. Może to mieć pewien wpływ na wydajność, ale nie mam żadnych liczb ...Dzięki temu
ref
można aliasować wartości zmienne, które używają - co oznacza, że można utworzyć dwie wartości odwołujące się do tej samej wartości mutowalnej: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!
źródło
Powiązane pytanie: „Wspomniałeś, że lokalne zmienne wartości nie mogą być przechwytywane przez zamknięcie, więc musisz zamiast tego użyć ref. Powodem tego jest to, że zmienne wartości przechwycone w zamknięciu muszą być przydzielone na stercie (ponieważ zamknięcie jest przydzielane na stos). ” z F # zmiennych zmiennoprzecinkowych vs pól obiektów
Myślę, że
let mutable
jest preferowany w stosunku do komórek odniesienia. Osobiście używam komórek referencyjnych tylko wtedy, gdy są potrzebne.Większość kodu, który piszę, nie używa zmiennych mutowalnych dzięki rekurencji i wywołaniom tail. Jeśli mam grupę zmiennych danych, używam rekordu. Dla obiektów, których używam,
let mutable
aby tworzyć prywatne zmienne zmienne. Tak naprawdę używam komórek referencyjnych tylko do zamknięć, ogólnie wydarzeń.źródło
Jak opisano w tym artykule na blogu MSDN w sekcji Uproszczone użycie zmiennych wartości , nie potrzebujesz już komórek ref dla lambd. Więc generalnie już ich nie potrzebujesz.
źródło
Ten artykuł autorstwa Briana może dostarczyć odpowiedzi.
Mutable są łatwe w użyciu i wydajne (bez zawijania), ale nie można ich przechwytywać w lambdach. Komórki ref można przechwytywać, ale są one pełne i mniej wydajne (? - nie jesteś tego pewien).
źródło
Możesz zajrzeć do sekcji Zmienne dane w wikibooku.
Dla wygody podajemy kilka odpowiednich cytatów:
źródło