2

私のコードでは、参照によっていくつかの構造体を渡し、それらを変更可能であると宣言し、&シンボルを使用しています。問題は、ある場所でフィールドが壊れていることです (リリース モードでのみ発生します)。その理由はまったくわかりません。

address-of 演算子の代わりに 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 ()

byref を使用して構造体を渡すことは、相互運用シナリオの場合、または構造体のフィールドを変更する場合にのみ役立ちます。ただし、これは私の場合ではありません。代わりに値 (約 20 バイト程度) で構造型を渡すことを検討する必要がありますか?

ありがとう!

4

1 に答える 1

6

あなたの例での の使用は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値を取り、ヒープ割り当て参照セルを作成する関数です。2 番目の例では、 のタイプはnisref<int>で、これは参照セルです。F# では、参照セルを引数としてbyrefパラメーターに渡すことができます。この場合、ヒープ割り当て (参照セル) オブジェクトのフィールドへのポインターが作成されます。

2 番目の例では、参照セルを作成し、参照セルへのポインターをmodify関数に渡し、!<ref>構文を使用して参照セルから値を取得します。最初の例では、関数を呼び出すときに新しい参照セルを作成しmodifyます (そして、の値がnスタックからヒープに割り当てられたセルにコピーされます)。セルは呼び出し後に使用されません (およびの値nは 15 のままです)

一方、mutable変数は単にスタックに格納され、変更することができます。主な違いは、ref常にヒープが割り当てられることです。呼び出された関数はスタック上の値を直接変更するmutableため、(原則として) 少し高速になる可能性があります。byref

于 2010-10-23T15:30:21.290 に答える