2016-09-22 51 views
7

我已經介紹過,數據默認情況下在F#中是不可變的。當我們爲某些變量重新賦值時,真正發生的是重新綁定變量的值,但設置一個新值是不同的。 重新綁定被稱爲陰影,而如果我們明確地不說變量的值是可變的,則設置新值是不可能的。影子與F中的設置值#

有人能詳細解釋我這個概念嗎?什麼是由

let var = "new_value" 

和設置新的價值陰影(重新綁定)之間的區別就像

var <- "new_value" 

這是一個時刻,即重新綁定過程中,我們創建另一個對象,我們在分配一個對象的地址變量,而第二個例子我們改變了價值本身?我從堆棧/堆棧理解了內存。我可能是錯的。

感謝

回答

9

陰影是,當你創建一個新結合使用相同的名稱作爲一個以前的綁定。這「隱藏」原始名稱,隱藏它,但不會更改或替換它。在FSI試試這個看:

let foo = 42 

let printFoo() = 
    printfn "%i" foo 

printFoo() ;; 

這將打印:

42 

val foo : int = 42 
val printFoo : unit -> unit 
val it : unit =() 

然後加:

// ... more code 
let foo = 24 

printfn "%i" foo // prints 24 
printFoo();; 

這將打印:

24 
42 

val foo : int = 24 
val it : unit =() 

注意,它仍然當您致電printFoo()時打印42 - 該功能看到原始(未遮蓋)的裝訂,但新的打印顯示新值。

使用<-變異值,需要一個可變綁定:

let mutable bar = 42 

let printBar() = 
    printfn "%i" bar 

printBar();; 

此,像上面,打印42.請注意,您與可變關鍵字這裏覆蓋默認不可改變的行爲。

你那麼內的可變綁定更改值:

bar <- 24 
printfn "%i" bar 
printBar();; 

這將打印24兩次,因爲與陰影版本,突變改變了原來的綁定。如果您在原始綁定中關閉mutable,則在使用<-時會出現錯誤。

2

每當我不知道究竟發生了我使用的工具,如ILSpy

例如:

let f() = 
    let x = Dictionary<int, string>() 
    let mutable x = ResizeArray<int> 16 
    x <- ResizeArray<int> 16 

使用ILSpy反編譯在C#代碼就變成:

public static void f() 
{ 
    Dictionary<int, string> x = new Dictionary<int, string>(); 
    List<int> x2 = new List<int>(16); 
    x2 = new List<int>(16); 
} 

這是更明顯的是陰影和設置有什麼區別。

影子x創建一個名稱爲x2的新變量。

設置屬於正常賦值。

4

要增加Reed Copsey的出色答案,如果您正在編寫一個循環來更改某種累加器的值,您可以將原始值設置爲mutable。例如,你可以做到這一點。

let mutable acc = 0 // declaration 
for i in 1..100 do 
    acc <- acc + i // assignment 

這是C#代碼或多或少相當於:

var acc = 0; 
for (int i = 1; i <= 100; i++) 
{ 
    acc = acc + i; // assignment 
    // Another way to write this: 
    // acc += i; 
} 

然而,陰影,因爲在這個F#片段:

let acc = 0 // declaration 
for i in 1..100 do 
    let acc = acc + i // another declaration only within the loop 

你實際上並不做任何事情有用!!第二個聲明僅在for循環內有作用域,它不會更改原始acc的值。

粗略C#相當於將是這樣:

var acc = 0; // declaration 
for (int i = 1; i <= 100; i++) 
{ 
    var acc2 = acc + i; // another declaration only within the loop 
} 

注意,使用acc(而不是acc2)的內部變量將在C#中不能編譯,因爲它沒有陰影在這方面。

陰影的使用是,它可以防止在你不需要的代碼塊中使用原始變體。所以有一個可以擔心的變量。