【问题标题】:immutable in F#在 F# 中不可变
【发布时间】:2012-06-24 19:42:14
【问题描述】:

我知道 F# 中的变量默认情况下是不可变的。 但是,例如在 F# 交互中:

  > let x = 4;;

val x : int = 4

> let x = 5;;

val x : int = 5

> x;;
val it : int = 5
> 

所以,我将 4 分配给 x,然后将 5 分配给 x,它正在改变。这是正确的吗?它应该给出一些错误或警告吗?或者我只是不明白它是如何工作的?

【问题讨论】:

标签: f# immutability shadowing


【解决方案1】:

当您编写let x = 3 时,您将标识符x 绑定到值3。如果您在同一范围内再次执行此操作,则您声明了一个新标识符,该标识符隐藏了前一个标识符,因为它具有相同的名称。

在 F# 中改变一个值是通过破坏性更新运算符 <- 完成的。对于不可变的值,这将失败,即:

> let x = 3;;

val x : int = 3

> x <- 5;;

  x <- 5;;
  ^^^^^^

stdin(2,1): error FS0027: This value is not mutable

要声明可变变量,请在let 之后添加mutable

let mutable x = 5;;

val mutable x : int = 5

> x <- 6;;
val it : unit = ()
> x;;
val it : int = 6

但是,您可能会问,两者之间有什么区别?一个例子可能就足够了:

let i = 0;
while i < 10 do
    let i = i + 1
    ()

尽管看起来,这是一个无限循环。在循环内声明的i 是一个不同的i,它隐藏了外部的i。外层是不可变的,因此它始终保持其值0 并且循环永远不会结束。正确的写法是使用可变变量:

let mutable i = 0;
while i < 10 do
    i <- i + 1
    ()

【讨论】:

    【解决方案2】:

    x 没有改变,只是被下一个声明隐藏了。 例如:

    > let x = 4;;
    val x : int = 4
    > let x = "abc";;
    val x : string = "abc"
    >
    

    【讨论】:

    • 隐藏和不可变有什么区别?这是否意味着我仍然可以获得以前的 x 值?
    • @Alex 查看我的答案以了解差异。
    【解决方案3】:

    您没有将 5 分配给 x,而是定义了一个新变量。

    以下示例显示有两个不同的变量。 (它还表明你可以“访问”旧的 x 如果它在一个闭包中,由另一个函数使用):

    let x = 5;;
    let f y = y+x;;
    f 10;;
    let x = 0;;
    f 10;;
    

    产量

    >
    val x : int = 5
    
    >
    val f : int -> int
    > val it : int = 15
    >
    val x : int = 0
    
    > val it : int = 15
    

    如您所见,对 f 的两次调用都使用第一个变量 x。定义let x = 0;; 定义了一个新变量x,但没有重新定义f

    【讨论】:

      【解决方案4】:

      这是一个说明 F# 中标识符“阴影”(即隐藏)的最小示例:

      let x = 0
      do //introduce a new lexical scope
          let x = 1 //"shadow" (i.e. hide) the previous definition of x
          printfn "%i" x //prints 1
      //return to outer lexical scope
      printfn "%i" x //prints 0, proving that our outer definition of x was not mutated by our inner definition of x
      

      您的示例实际上有点复杂,因为您在 F# Interactive (FSI) 中工作。 FSI 在您的示例中动态发出类似于以下内容的代码:

      module FSI_0001 =
          let x = 4;;
      
      open FSI_0001 //x = 4 is now available in the top level scope
      module FSI_0002 =
          let x = 5;;
      
      open FSI_0002 //x = 5 is now available in the top level scope, hiding x = 4
      module FSI_0003 =
          let it = x;;
      
      open FSI_0003
      //... subsequent interactions
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多