f# - address-of 和 ref 运算符之间的差异

标签 f# struct operators byref

在我的代码中,我通过引用传递一些结构,声明它们可变并使用 & 符号。问题是在某些地方字段已损坏(仅发生在 Release模式下),我完全不知道原因。

我找到了一个修复方法,使用 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 个字节左右)?

谢谢!

最佳答案

使用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直接修改堆栈上的值。

关于f# - address-of 和 ref 运算符之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4004594/

相关文章:

ubuntu - 在 Ubuntu 10.04 上获取 F#

c++ - 将结构复制(使用赋值)到 union 内的结构导致段错误

我可以在结构中存储通用数组吗?

angularjs - 如何在 AngularJS 中对两个 Scope 值求和

visual-studio - Visual Studio F# 交互窗口由哪个进程托管?

f# - 具有混合参数化类型的列表

c++ - .get() 和 -> 与智能指针之间有区别吗?

php - 为什么使用 !== FALSE 来检查 php 中的 stripos?

c# - 如何避免从 F# 库返回 Task<Microsoft.FSharp.Core.Unit>

复制结构的组件会删除同一结构的另一个组件