将大序列作为函数参数传递

Shr*_*roy 4 f# pass-by-reference pass-by-value

这真是一个简单的问题(但我似乎无法在MSDN文档中找到答案).

如果我在F#中将大型序列和对象作为函数参数传递,它们是否总是按值复制,除非我提供了byref关键字?问题是,我无意修改参数,但同时,我不想每次调用函数时都要复制大对象.

Bri*_*ian 10

我不同意人们在这里使用的术语.

我想这句话是:一切都在.NET是通过按值默认情况下,例外的是如refout参数在C#和byrefF#中的参数.但是,序列和数组以及大多数其他类型(除了结构和基元)都是对象引用,这意味着当您将它们作为参数传递(按值)时,您只传递对实体的引用,并且调用者和被调用者共享堆上的同一个实际实体.所以引用是通过值传递的,但引用本身只是小事,而它们指向的对象实体(包含所有数据)是在堆上共享的大事.


Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

如果您正在使用集合传递byref,那么您实际上是在向堆栈分配的引用传递引用,该引用实际上指向堆分配的数据结构.但是,byref在F#中很少使用 - 在调用C/C++或COM库时,您主要需要它来实现互操作性.