【问题标题】:F# handling values and referencesF# 处理值和引用
【发布时间】:2011-02-14 03:42:18
【问题描述】:

我需要了解关于 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# 方法是什么? (我的意思是价值与参考)。

【问题讨论】:

标签: .net f# reference


【解决方案1】:

使用引用类型和值类型时,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# 中的使用是有意义的,因为类型是不可变的 - 当您创建包含相同数据的两个值时,它们将始终相同。如果它们是可变的,您可以更改一个,它们将不再相等 - 这就是为什么对可变类型使用引用相等更有意义。

【讨论】:

  • 好的,谢谢……还有一件事……f#中的所有内置类型,它们是结构还是非结构?我的意思是它们是价值类型吗?还是不行?
  • @Andry:原则上没关系——因为它们是不可变的并且具有结构相等的语义,它们的行为是相同的。从实际的角度来看,它可能很重要(对于性能)。因此,答案是所有标准 F# 类型都是引用类型。您可以通过在对象类型声明中添加 [<Struct>] 来定义值类型,但可区分的联合始终是引用类型。
  • 谢谢 Tomas,在处理 f# 时,你永远是我的光... :)
【解决方案2】:

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

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

或者更好:

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

正如 Tomas 指出的那样,(=) 的行为可能有点微妙。

在我看来,实际上没有任何合乎逻辑的选择; myvar2 还可能包含什么?没有任何通用机制可以复制任意类型的对象,因此唯一有意义的行为是 myvarmyvar2 包含相等的引用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2020-08-19
    • 2013-03-18
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多