2014-11-24 34 views
2

我想我理解這裏發生了什麼,但是我真的很感謝有人對它發生的原因有所瞭解。我有一個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") 
... 

Inside S.addSymbol我可以看到新的鍵/值被添加到表中,但S.names沒有得到更新。相反,如果我叫addSymbol這樣的:

ignore (
    let tmp = S.names 
    s.addSymbol tmp "newName" 
) 

然後我可以看到TMP正與新的鍵/值對更新,但仍S.names沒有更新。

下面是我認爲我知道的:ref機制沒有什麼錯 - 它正確地更新了函數內部和外部的指示對象。但是對於靜態成員來說似乎有點奇怪 - 就像,每次都只給我一個相同的靜態引用,而是複製'a',然後爲此創建一個新的引用。

我有這個權利嗎?如果是這樣,爲什麼它這樣做?我能做些什麼來使其表現得更明智?

在此先感謝。

+0

@Vandroiy已經診斷出你的直接問題,但是這裏有一個額外的想法:如果你要改變一個集合,那麼使用標準的.NET可變集合而不是包含一個不可變集合的引用通常會更有意義,你更新到位。在你的情況下,這意味着使用'System.Collections.Generic.Dictionary <_,_>'而不是'Map <_,_> ref'。 – kvb 2014-11-24 21:33:54

+0

我確實考慮過使用.net集合,但決定不採用這種方式,部分是出於架構原因(我有很多表需要保持同步,所以我不想公開Add方法),但也是因爲它感覺就像一個警察 - 我剛剛開始F#,並且我試圖以「正確」的方式來做事,而不是僅僅爲了C#而努力。我從指導中注意到,應該使用對象來表示大事物和功能。不知道我的問題是什麼,但我認爲我表達的意識缺乏明智的判斷:-)。 – 2014-11-25 09:26:18

回答

6

靜態成員names屬性,不是靜態值。它在內部是一個函數,每次調用它時都會創建一個新地圖。

如果該值必須在該類中,請使用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 

很多時候,類不公開參考單元本身,而是讀取,添加或刪除名稱的成員。然後,Names將返回!names - 或名稱將是一個普通的可變而不是參考單元格 - 而其他方法(如AddName)會更改該值。如果不需要這種封裝,請參閱kvb關於如何將此示例縮短爲只有一個成員的評論。 (謝謝你的提示!)


備選:通常,這是其中使用F#的模塊的情況。只要定義

let names = ref Map.empty : Map<string, S> ref 

let mutable names = Map.empty : Map<string, S> 

在一個模塊中,有額外的訪問限制或封裝的要求。

+1

您也可以使用「自動實現的屬性」:'靜態成員val名稱:映射 ref = ref Map.empty' – kvb 2014-11-24 21:29:58

+0

謝謝,Vandroiy--這是一個非常明確的解釋。在你的第一個建議中,這是一個恥辱,它需要額外的名字。我想我更喜歡第二個答案。但是kvb的答案可能是實現我想要做的最簡潔的方法,而且我剛剛學到了很多有關val的工作,所以謝謝,對你也是如此。但是,我確實發現,給定的靜態成員每次都會創建一個新對象,而val特別意味着在構建時創建了一次未裝飾的靜態成員是非常沒用的東西 - 除非我失蹤什麼? – 2014-11-25 09:17:09

+0

@Jules這是一個封裝問題。通常情況下,您將擁有私有值來保存原始數據結構,然後使用成員進行允許的操作。 「名稱」可以取消引用該值,以便它只讀取地圖,但不能更改它。然後,像「AddName」這樣的成員可以允許某些明確定義的操作。它取決於期望的安全需求或圍繞可變值的限制。 (我編輯了答案,指出了kvb的評論並提到了這一點。) – Vandroiy 2014-11-25 14:37:06