2016-09-22 5 views
7

私はこのデータが導入されましたが、デフォルトではF#では変更できません。ある変数に値を再割り当てすると、実際には変数の値が再バインドされますが、新しい値を設定することは別のことです。 RebindingはShadowingと呼ばれますが、変数の値が変更可能であると明示的に言わないと新しい値を設定することは不可能です。F#のシャドウイングとセッティングの値

誰でもこの概念を詳しく説明できますか?何

var <- "new_value" 

はこの瞬間が再バインド時に、我々は別のオブジェクトを作成することであるように

let var = "new_value" 

し、新しい値を設定することにより、(再バインド)をシャドーイングとの違いだと私たちは中のに対し、変数にそのオブジェクトのアドレスを割り当て2番目の例では、値自体を変更しますか?私はメモリからヒープ/スタックの理解からそれをもたらした。私は間違っている可能性があります。あなたはそれが前のバインディングと同じ名前を使用して結合新しいを作成するときに

おかげ

答えて

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

のようなツールを使用して何が起こっているのか疑問に思うたび:

それはなったC#のコードでそれを逆コンパイルするILSpyを使用し
let f() = 
    let x = Dictionary<int, string>() 
    let mutable x = ResizeArray<int> 16 
    x <- ResizeArray<int> 16 

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 

あなたが実際に何もしていません有用!! 2番目の宣言は、forループ内のスコープのみを持ち、元のaccの値は変更しません。それはこの文脈でシャドウイングを持たないように内部変数の(代わりacc2の)accを使用して、C#でコンパイルされないであろうこと

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

粗いC#の同等のこのあろう。

シャドーイングを使用すると、元のバリアントを不要なコードブロックで使用できなくなります。したがって、心配する変数は1つ少なくなります。

関連する問題