为什么禁用类型如
type t = A of int | B of string * mutable int
虽然允许这样的类型:
type t = A of int | B of string * int ref
答案 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!