4

これは本当に簡単な質問です (しかし、MSDN ドキュメントで答えを見つけることができなかったようです)。

F# で大きなシーケンスとオブジェクトを関数パラメーターとして渡す場合、byref キーワードを指定しない限り、それらは常に値によってコピーされますか? 問題は、引数を変更するつもりはありませんが、同時に、関数を呼び出すたびに大きなオブジェクトをコピーしたくないということです。

4

4 に答える 4

10

ここで人々が使用している用語には同意しません。

私はそれを次のように表現します: .NET のすべては既定で値渡しです。例外はrefoutC# のbyrefパラメーターと F# のパラメーターなどです。ただし、シーケンスと配列、およびその他のほとんどの型 (構造体とプリミティブを除く) はオブジェクト参照です。ヒープ上の同じ実体。したがって、参照は値によって渡されますが、参照自体は小さなものにすぎませんが、参照が指す (すべてのデータを含む) オブジェクト エンティティはヒープ上で共有される大きなものです。

于 2012-06-27T15:33:40.837 に答える
5

コメントで述べたように、F# は基本的に C# と同じメカニズムを使用します。これは、値の型( や構造体などのプリミティブ値int)floatのみがスタックにコピーされ、他のすべての型は参照によって渡されることを意味します。これには、すべてのコレクション (シーケンスseq<'T>、配列'T[]、および不変の機能リストlist<'T>) が含まれます。

不変型 (機能的で副作用のないもの) を使用list<'T>seq<'T>ている場合、参照を渡すこととオブジェクトをコピーすることに違いはありません。パフォーマンスは別として、ランタイムは常にそれらを参照として渡しますが、心配する必要はありません。これは、プログラムを最適化している場合を除きます (受け渡しメカニズムを変更できたとしても、動作は変わりません)。

(変更可能な) 配列の場合、John Palmer の回答の例を見ると、動作が参照渡しであることを簡単に確認できます。

補足として、byrefスタック割り当ての可変変数への参照を作成する場合は、キーワード (または型) を使用します。つまり、値型の変数への参照を渡すために使用できます。

let bar (a:byref<int>) =    // takes reference to a (stack-allocated) 'int' variable
  a <- 42                   // mutate the variable

let mutable foo = 10        // declare a mutable variable
bar &foo                    // pass reference to the `bar` function

を使用してコレクションを渡す場合byref、実際には、実際にはヒープ割り当てデータ構造を指すスタック割り当て参照への参照を渡します。ただし、byrefF# ではめったに使用されません。主に、C/C++ または COM ライブラリを呼び出す際の相互運用性のために必要になります。

于 2012-06-27T11:24:09.180 に答える
2

デフォルトでは、シーケンス/リスト/配列は参照によって渡されます

例えば

let mutate (arr:int[]) =
    arr.[0] <- 1

let t = Array.zerocreate 1
mutate t
printfn "%i" (t.[0]) //prints 1
于 2012-06-27T10:47:02.460 に答える
0

値は不変であるため、渡した同じシーケンスが変更または使用されます。オブジェクトは毎回コピーされません。

ただし、シーケンスを変更すると、新しい値で新しいシーケンスが作成されます。

于 2012-06-27T10:52:06.823 に答える