2010-10-23 36 views
1

在我的代碼中,我通過引用傳遞了一些結構,聲明它們是可變的並使用&符號。問題是,在某些地方,這些字段已損壞(僅在發佈模式下發生),我不知道爲什麼。地址和ref操作符之間的差異

我發現一個修復,使用ref關鍵字,而不是地址的運營商。我知道你可以自由地交換它們(在實例成員參數的情況下),但爲什麼它能解決我的問題?

下面是說明這是一個小的代碼示例:

[<Struct>] 
type MyStruct = 
    val mutable private i : int 
    val mutable private f : float 
    new (a, b) = { i = a; f = b } 
    member t.I = t.i 
    member t.F = t.f 

type Printer() = 
    member t.Print(data : MyStruct byref) = printfn "%d %f" data.I data.F 

let bar (p : Printer) = 
    let mutable x = new MyStruct(2, 8.0) 
    p.Print(&x) 

let foo (p : Printer) = 
    let mutable y = new MyStruct(2, 8.0) 
    p.Print(ref y) // What is exactly the difference, under the hood? 

let main() = 
    foo (new Printer()) 
    bar (new Printer()) 
do main() 

傳遞結構與按地址似乎有用的,只有互操作的情況,或者如果你想變異結構的領域。但這不是我的情況。我應該考慮通過值來傳遞結構類型(約20字節左右)嗎?

謝謝!

+3

我對F#不太瞭解,所以很遺憾沒有答案給你。但我認爲避免這個問題的一種方法不是使用可變結構的邪惡。 – Joren 2010-10-23 15:27:04

回答

5

在你的例子中使用的ref可能不會恰好是你想要什麼就寫:

let modify (data:int byref) = data <- 10 

let foo() = 
    let mutable n = 15 // Note: Compiles without 'mutable' 
    modify (ref n) 
    printfn "%d" n // Prints '10'!! 

你可能想是這樣的:

let foo() = 
    let n = ref 15 
    modify n 
    printfn "%d" (!n) // Prints '15' 

那麼,有什麼區別? ref是一個函數,它接受一個值並創建一個堆分配的引用單元。在第二個示例中,n的類型是ref<int>,它是參考單元格。 F#允許將參考單元作爲參數傳遞給byref參數 - 在這種情況下,它會創建一個指向堆分配(引用單元)對象字段的指針。

在第二個示例中,我們創建參考單元,將指針傳遞給modify函數的參考單元,然後使用!<ref>語法從參考單元獲取值。在第一個示例中,我們在調用modify函數(並將n的值從堆棧複製到堆分配單元格)時創建新的參考單元格。呼叫後單元格不使用(並且n的值保留15)

另一方面,mutable變量僅存儲在堆棧中,可以進行變異。主要區別在於ref始終是堆分配 - 使用mutable可能(原則上)速度更快一些,因爲調用函數byref會直接修改堆棧中的值。

相關問題