【发布时间】:2014-11-24 18:25:59
【问题描述】:
我想我明白这里发生了什么,但我非常感谢有人能解释一下为什么会发生这种情况。
基本上(我在这里动态编码,以给出最简单的说明)我有一个类 S,除其他外,它维护一个符号表,将名称与类的对象相关联。所以,在我定义的类里面:
static member (names:Map<string,S> ref) = ref Map.empty
...然后,我也在 S 中定义:
member this.addSymbol (table: Map<string,S> ref) (name:string)
table := (!table).Add(name, this)
this
我从其他地方调用它,因此:
ignore (s.addSymbol S.names "newname")
...
在 S.addSymbol 内部,我可以看到新的键/值被添加到表中,但 S.names 没有得到更新。相反,如果我这样调用 addSymbol:
ignore (
let tmp = S.names
s.addSymbol tmp "newName"
)
然后我可以看到 tmp 正在使用新的键/值对进行更新,但 S.names 仍然没有得到更新。
以下是我认为我所知道的:ref 机制没有任何问题——它在函数内部和外部都正确地更新了所指对象。但是静态成员似乎有些奇怪 - 就像,它不是每次都给我相同的静态 ref 'a,而是复制 'a,然后为此创建一个新的 ref。
我做对了吗?如果是这样,它为什么要这样做?我该怎么做才能让它表现得更明智?
提前致谢。
【问题讨论】:
-
@Vandroiy 已经诊断出你的直接问题,但这里有一个额外的想法:如果你要改变一个集合,那么使用标准的 .NET 可变集合而不是引用通常更有意义包装您更新的不可变集合。在您的情况下,这意味着使用
System.Collections.Generic.Dictionary<_,_>而不是Map<_,_> ref。 -
我确实考虑过使用 .net 集合,但最终决定不这样做,部分原因是架构上的原因(我有很多需要保持同步的表,所以我不想暴露添加方法),但也因为它感觉像是一种逃避——我刚刚开始使用 F#,并且我正在尝试以“正确”的方式做事,而不是仅仅使用 C# 类似的东西。我从指导中注意到,人们应该将对象用于大的东西,而将功能用于精细的东西。不知道我的问题是什么,但我想我是在表达一种缺乏知情判断的感觉:-)。