F#处理值和引用

时间:2011-02-13 18:49:06

标签: .net f# reference

我需要了解一些关于F#非常重要的事情:它如何处理引用和值。 我知道F#定义了不可变和可变对象,也知道了原因。

但有一件事我不知道:对象是如何处理的?

我的意思是,在C#中,一切都是一个指针,当为一个对象分配另一个的引用时,数据是相同的,我们将有两个指向相同数据的指针。

所以在C#中如果我有这个:

Object myobj1 = new Object();
Object myobj2 = myobj1;
bool myobj1 == myobj2; // It is true

那么,f#怎么样?

let myvar: MyObj = new MyObj ()
let myvar2: MyObj = myvar

这里的情况如何? 作业是否涉及复制?或不。

而且,一般来说,这个主题的f#方法是什么? (我的意思是价值与参考)。

2 个答案:

答案 0 :(得分:7)

使用引用类型和值类型时,F#的行为与C#类似。

  • 如果您有引用类型,则它将使用对堆中实例的引用。
  • 当您有值类型(内置,在C#中声明或在F#中使用Struct属性声明)时,
    将值分配给另一个值或作为参数传递时,将复制该值。

唯一值得注意的区别是标准F#类型(有区别的联合,记录,列表,数组和元组)具有结构相等语义。这意味着它们通过比较存储在它们中的实际值而不是通过比较引用(即使它们是引用类型)进行比较。例如,如果您创建两个包含相同数据的元组列表:

> let l1 = [ ("Hello", 0); ("Hi", 1) ]
  let l2 = [ ("Hi", 1); ("Hello", 0) ] |> List.rev;;
(...)

> l1 = l2;;
val it : bool = true

即使列表和元组是引用类型,也会得到true。但是,如果比较参考文献(编辑:添加样本灵感来自kvb ):

> System.Object.ReferenceEquals(l1, l2);;
val it : bool = false

使用结构相等在F#中是有意义的,因为类型是不可变的 - 当您创建包含相同数据的两个值时,它们将始终相同。如果它们是可变的,你可以改变它们并且它们将不再相等 - 这就是为什么使用引用相等来为可变类型更有意义。

答案 1 :(得分:6)

您可以通过以下简单的实验说服自己,F#的行为与C#的行为相同:

printfn "%b" (myvar = myvar2)  // true

或者更好:

printfn "%b" (obj.ReferenceEquals(myvar, myvar2)) // true

因为Tomas指出,(=)的行为可能有点微妙。

从我的角度来看,没有任何合理的选择; myvar2可能还包含哪些内容?复制任意类型的对象没有任何通用机制,因此唯一有意义的行为是myvarmyvar2包含相同的引用。