F# 可变参考单元不';不能使用静态成员

F# 可变参考单元不';不能使用静态成员,f#,ref,F#,Ref,我想我知道这里发生了什么,但我真的很感激有人能解释为什么会发生 基本上(为了给出最简单的说明,我在这里动态地编写代码)我有一个类S,除其他外,它维护一个与类对象的名称相关的符号表。因此,在我定义的类中: static member (names:Map<string,S> ref) = ref Map.empty member this.addSymbol (table: Map<string,S> ref) (name:string) table := (!t

我想我知道这里发生了什么,但我真的很感激有人能解释为什么会发生

基本上(为了给出最简单的说明,我在这里动态地编写代码)我有一个类S,除其他外,它维护一个与类对象的名称相关的符号表。因此,在我定义的类中:

static member (names:Map<string,S> ref) = ref Map.empty
member this.addSymbol (table: Map<string,S> ref) (name:string)
    table := (!table).Add(name, this)
    this
在S.addSymbol中,我可以看到新的键/值被添加到表中,但是S.names没有得到更新。相反,如果我这样称呼addSymbol:

ignore (
    let tmp = S.names
    s.addSymbol tmp "newName"
)
然后我可以看到tmp被更新为新的键/值对,但是S.names仍然没有得到更新

以下是我认为我知道的:ref机制没有任何问题——它在函数内部和外部都正确地更新referent。但是这个静态成员似乎有点奇怪,它不是每次都给我相同的静态ref'a,而是复制'a,然后为它创建一个新的ref

我说得对吗?如果是,为什么要这样做?我该怎么做才能让它表现得更理智呢


提前感谢。

静态成员
名称
是一个属性,而不是静态值。它在内部是一个函数,每次调用它时都会创建一个新映射

如果该值必须在类中,请使用
static let
在类中定义它。这样,引用单元格只创建一次

type S () =
    static let names = ref Map.empty : Map<string, S> ref
    static member Names = names

S.Names := ["Don", S()] |> Map.ofList
S.Names // gives map with one element

让可变名称=Map.empty:Map

在模块中,需要附加访问限制或封装。

您也可以使用“自动实现的属性”:
静态成员val name:Map ref=ref Map.empty
谢谢,Vandroy-这是一个非常清楚的解释。很遗憾,在你的第一个建议中,它需要那个额外的名字。我想我更喜欢第二个答案。但是kvb的答案可能是实现我想要做的事情的最简洁的方式,我刚刚了解了很多val所做的事情,所以也要感谢你。不过,我确实想到,给定的静态成员每次都会创建一个新对象,而val特别意味着在构建时创建一次该字段,一个未修饰的静态成员是一个非常无用的东西——除非我遗漏了什么?@Jules这是一个封装问题。通常,您会使用私有值来保存原始数据结构,然后使用成员对其执行允许的操作
Names
可以取消对值的引用,因此它只能读取映射,但不能更改它。然后,像
AddName
这样的成员可以允许某些定义良好的操作。这取决于所需的安全需求或可变值周围的限制。(我编辑了答案,指向kvb的评论并提到了这一点。)@Vandroy已经诊断出了您的直接问题,但这里还有一个额外的想法:如果您要对集合进行变异,那么使用标准的.NET可变集合通常比使用一个引用包装您就地更新的不可变集合更有意义。在您的情况下,这将意味着使用<代码> Stasy.Suff.Grima.字典>代码>而不是<代码> MAPREF 。我确实考虑过使用.NET集合,但我决定反对它,部分原因是由于架构原因(我有很多需要同步的表,所以我不想公开Add方法),但也因为这感觉像是一种逃避——我才刚刚开始F#,我正试图以“正确”的方式做事,而不是像C#一样。我从指南中注意到,一个人应该使用对象来处理大的东西,使用函数来处理好的东西。不确定我的问题是什么,但我想我表达了一种缺乏明智判断的感觉:-)。
type S () =
    static let names = ref Map.empty : Map<string, S> ref
    static member Names = names

S.Names := ["Don", S()] |> Map.ofList
S.Names // gives map with one element
let names = ref Map.empty : Map<string, S> ref
let mutable names = Map.empty : Map<string, S>