F# 与可变匹配

F# match with mutable

刚开始玩 F#,我想在我的应用程序中创建一些可变模型来玩,使用 F# discriminated union 而不是 class 层次结构。然而,似乎没有办法 "downcast" 一个受歧视的联合并且 "match with" 不会传播可变性。我该怎么办?

type Foo = {
    mutable x: int
}

type FooBar = 
    | Foo of Foo
    | Bar

let f = {x = 2};
do f.x <- 3; //All ok

let fb = Foo {x = 1}
do match fb with
    | Foo {x = x} -> x <- 2 //"This value is not mutable"
    | Bar -> ()

你的问题是,你 match/deconstruct fb 变成了一个新的 pattern/value x : int(这与 f.x 完全不一样! ) 当然是不可变的(默认情况下 F# 中的 bindings/values)。

如果您不给两者(值和模式)相同的名称,您可能会看得更清楚:

> match fb with Foo { x = y } -> y;;
val it : int = 1

看到你将 xy 匹配,所以 y 将获得 x 的值(但不会可变)


情况 C#

让我们看看 C# 中的类似情况是什么

假设你有 Foo class:

class Foo { public int x { get; set; } }

FooBar base-class with

class Foo2 : FooBar 
{ 
    public Foo Value { get; } 
}

(我对 ctors 进行了条纹处理,因为我太懒了 - 你明白了)

现在你会这样做:

var fb = new Foo2(new Foo(1));
var x = fb.Value.x;
x := 2;

你认为 fb.Value.x 会是 2 还是 1? ;)


如何进行模式匹配/变异

使用

let fb = Foo {x = 1}
do match fb with
    | Foo f -> f.x <- 2
    | Bar -> ()

相反 - 这将从 fb 解构 f 然后你可以设置可变记录字段 f.x

但我建议不要通过尝试如何使用 mutable 值来开始学习 F# - 尝试尽可能多地使用 immutability 来学习尽你所能:)