影子与F中的设置值#
我已经介绍过,数据默认情况下在F#中是不可变的。当我们为某些变量重新赋值时,真正发生的是重新绑定变量的值,但设置一个新值是不同的。 重新绑定被称为阴影,而如果我们明确地不说变量的值是可变的,则设置新值是不可能的。影子与F中的设置值#
有人能详细解释我这个概念吗?什么是由
let var = "new_value"
和设置新的价值阴影(重新绑定)之间的区别就像
var <- "new_value"
这是一个时刻,即重新绑定过程中,我们创建另一个对象,我们在分配一个对象的地址变量,而第二个例子我们改变了价值本身?我从堆栈/堆栈理解了内存。我可能是错的。
感谢
阴影是,当你创建一个新结合使用相同的名称作为一个以前的绑定。这“隐藏”原始名称,隐藏它,但不会更改或替换它。在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
,则在使用<-
时会出现错误。
每当我不知道究竟发生了我使用的工具,如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
的新变量。
设置属于正常赋值。
要增加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#中不能编译,因为它没有阴影在这方面。
阴影的使用是,它可以防止在你不需要的代码块中使用原始变体。所以有一个可以担心的变量。