これは本当に簡単な質問です (しかし、MSDN ドキュメントで答えを見つけることができなかったようです)。
F# で大きなシーケンスとオブジェクトを関数パラメーターとして渡す場合、byref キーワードを指定しない限り、それらは常に値によってコピーされますか? 問題は、引数を変更するつもりはありませんが、同時に、関数を呼び出すたびに大きなオブジェクトをコピーしたくないということです。
これは本当に簡単な質問です (しかし、MSDN ドキュメントで答えを見つけることができなかったようです)。
F# で大きなシーケンスとオブジェクトを関数パラメーターとして渡す場合、byref キーワードを指定しない限り、それらは常に値によってコピーされますか? 問題は、引数を変更するつもりはありませんが、同時に、関数を呼び出すたびに大きなオブジェクトをコピーしたくないということです。
ここで人々が使用している用語には同意しません。
私はそれを次のように表現します: .NET のすべては既定で値渡しです。例外はref
、out
C# のbyref
パラメーターと F# のパラメーターなどです。ただし、シーケンスと配列、およびその他のほとんどの型 (構造体とプリミティブを除く) はオブジェクト参照です。ヒープ上の同じ実体。したがって、参照は値によって渡されますが、参照自体は小さなものにすぎませんが、参照が指す (すべてのデータを含む) オブジェクト エンティティはヒープ上で共有される大きなものです。
コメントで述べたように、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
、実際には、実際にはヒープ割り当てデータ構造を指すスタック割り当て参照への参照を渡します。ただし、byref
F# ではめったに使用されません。主に、C/C++ または COM ライブラリを呼び出す際の相互運用性のために必要になります。
デフォルトでは、シーケンス/リスト/配列は参照によって渡されます
例えば
let mutate (arr:int[]) =
arr.[0] <- 1
let t = Array.zerocreate 1
mutate t
printfn "%i" (t.[0]) //prints 1
値は不変であるため、渡した同じシーケンスが変更または使用されます。オブジェクトは毎回コピーされません。
ただし、シーケンスを変更すると、新しい値で新しいシーケンスが作成されます。