为什么FSharp交互允许mutable let?

时间:2013-04-21 19:12:36

标签: f# read-eval-print-loop

在FSI中输入

> let a = 10;;

val a : int = 10

> let a = a + 1;;

val a : int = 11

看起来我在这里有一个可变变量?我错过了什么吗?

2 个答案:

答案 0 :(得分:5)

这不是一个可变的值。但是你使用阴影:在F#中,当在某个范围内声明的变量(决策块,方法或内部类)与在外部范围内声明的变量具有相同的名称时,会发生值阴影。

如果你想拥有一个可变值,F#中有一个语法:

let mutable a = 10
a <- a + 1

答案 1 :(得分:5)

正如Arthur已经解释的那样,你看到的是 shadowing ,这意味着名为a的原始“变量”被一个名为a的新“变量”隐藏(我在引号中使用变量,因为它们实际上是不可变的值)。

要查看差异,您可以捕获函数中的原始值,然后在隐藏原始值后打印该值:

> let a = 10;;                // Define the original 'a' value
val a : int = 10

> let f () = a;;              // A function captures the original value    
val f : unit -> int

> let a = 42;;                // Define a new value hiding the first 'a'
val a : int = 42

> f();;                       // Prints the original value - it is not mutated!
val it : int = 10

可悲的是,您不能使用完全相同的代码来查看let mutable的行为(因为F#不允许在闭包中捕获可变引用),但是当您使用引用单元格时可以看到变异(即,在堆中存储可变值的简单对象):

> let a = ref 10;;             // Create a mutable reference cell initialized to 10
val a : int ref = {contents = 10;}

> let f () = !a;;              // A function reads the current value of the cell    
val f : unit -> int

> a := 42;;                    // Overwrite the value in the cell with 42
val it : unit = ()

> f();;                        // Prints the new value - it is mutated
val it : int = 42

您可以在F#interactive中逐行运行代码,但是当您复制整个代码段(输入行)并将它们放在普通的F#代码中时,它会完全相同 - 例如在函数或模块中。 ;;只是结束F#交互输入中的行(我在F#Interactive窗口中键入代码),但在普通代码中不需要它,因为F#使用缩进来查找语句结束的位置。