Why is disabled types like
type t = A of int | B of string * mutable int
while such types are allowed:
开发者_运维问答type t = A of int | B of string * int ref
The question is, how would you modify the value of a mutable element of discriminated union case? For ref
types, this is quite easy, because ref
is a reference cell (a record actually) which contains the mutable value:
match tval with
| B(str, refNum) -> refNum := 4
We extract the reference cell and assign it to a new symbol (or a new variable) refNum
. Then we modify the value inside the ref cell, which also modifies tval
, because the two references to the cell (from discriminated union case and from refNum
variable) are aliased.
On the other hand, when you write let mutable n = 0
, you're creating a variable, which can be directly mutated, but there is no cell holding the mutable value - the variable n
is directly mutable. This shows the difference:
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!)
So, to answer your question - there is no way to directly refer to the value stored inside the discriminated union case. You can only extract it using pattern matching, but that copies the value to a new variable. This means that there isn't any way you could modify the mutable
value.
EDIT
To demonstrate limitations of mutable
values in F#, here is one more example - you cannot capture mutable
values inside a closure:
let foo() =
let mutable n = 0
(fun () -> n <- n + 1; n) // error FS0407
I think the reason is same as with discriminated union cases (even though it's not as obvious in this case). The compiler needs to copy the variable - it is stored as a local variable and as a field in the generated closure. And when copying, you want to modify the same variable from multiple references, so aliasing semantics is the only reasonable thing to do...
Ref is a type (int ref = ref<int>
). Mutable is not a type, it's a keyword that allows you to update a value.
Example:
let (bla:ref<int>) = ref 0 //yup
let (bla:mutable<int>) = 3 //no!
精彩评论