类型定义中的“可变”

时间:2010-02-08 09:50:06

标签: f#

为什么禁用类型如

type t = A of int | B of string * mutable int

虽然允许这样的类型:

type t = A of int | B of string * int ref

2 个答案:

答案 0 :(得分:12)

问题是,你如何修改受歧视的工会案件的可变元素的价值?对于ref类型,这很容易,因为ref是一个包含可变值的引用单元格(实际上是一条记录):

match tval with
| B(str, refNum) -> refNum := 4

我们提取参考单元格并将其分配给新符号(或新变量)refNum。然后我们修改ref单元格中的值,它也修改tval,因为对单元格的两个引用(来自有区别的联合案例和来自refNum变量)是别名。

另一方面,当你写let mutable n = 0时,你正在创建一个可以直接变异的变量,但是没有单元格保存可变值 - 变量n是可以直接变异的。这表明了不同之处:

let mutable a = 10
let mutable b = a
b <- 5   // a = 10, b = 5

let a = ref 10
let b = a
b := 5   // a = 5, b = 5 (because of aliasing!)

所以,回答你的问题 - 没有办法直接引用存在于受歧视的联合案例中的值。您只能使用模式匹配来提取它,但会将值复制到新变量。这意味着您无法修改mutable值。

修改 为了证明F#中mutable值的限制,还有一个例子 - 你无法在闭包中捕获mutable值:

let foo() = 
  let mutable n = 0
  (fun () -> n <- n + 1; n) // error FS0407

我认为原因与受歧视的工会案件相同(即使在这种情况下并不那么明显)。编译器需要复制变量 - 它作为局部变量存储,并作为生成闭包中的字段存储。在复制时,您希望从多个引用中修改相同的变量,因此别名语义是唯一合理的事情......

答案 1 :(得分:5)

Ref是一种类型(int ref = ref<int>)。 Mutable不是一个类型,它是一个允许你更新值的关键字。

示例:

let (bla:ref<int>) = ref 0 //yup
let (bla:mutable<int>) = 3 //no!