F#:让mutable与ref

时间:2010-07-10 23:12:26

标签: f# mutable

首先,我承认这个问题可能是重复的;请告诉我。

我很好奇当需要可变性时,对于那些情况,一般的“最佳实践”是什么。 F#似乎为此提供了两种工具:let mutable绑定,它似乎像“大多数”语言中的变量一样工作,而参考单元(使用ref函数创建)需要显式解除引用才能使用

有几种情况,其中一个被“强制”为一个或另一个:.NET interop倾向于使用<-变量,而在工作流计算中,必须使用ref := 1}}。所以这些案例非常明确,但我很好奇在这些场景之外创建自己的可变变量时该怎么做。一种风格比另一种风格有什么优势? (也许对实施的进一步了解会有所帮助。)

谢谢!

5 个答案:

答案 0 :(得分:124)

我只能支持 gradbot 所说的内容 - 当我需要变异时,我更喜欢let mutable

关于两个实现和差异 - ref单元基本上由包含可变记录字段的非常简单的记录实现。您可以自己轻松地编写它们:

type ref<'T> =  // '
  { mutable value : 'T } // '

// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }

两种方法之间的显着差异是let mutable将可变值存储在堆栈上(作为C#中的可变变量),而ref将可变值存储在堆分配的字段中记录。这可能会对性能产生一些影响,但我没有任何数字......

由于这个原因,使用ref的可变值可能会有别名 - 这意味着您可以创建两个引用相同可变值的值:

let a = ref 5  // allocates a new record on the heap
let b = a      // b references the same record
b := 10        // modifies the value of 'a' as well!

let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10           // modifies the value of 'b' only!

答案 1 :(得分:18)

相关问题:“您提到闭包不能捕获本地可变值,因此您需要使用ref。原因是闭包中捕获的可变值需要是在堆上分配(因为闭包是在堆上分配的)。“来自F# ref-mutable vars vs object fields

我认为let mutable比参考单元格更受欢迎。我个人只在需要时才使用参考单元格。

由于递归和尾调用,我编写的大多数代码都不使用可变变量。如果我有一组可变数据我使用记录。对于对象,我使用let mutable来创建私有可变变量。我只使用参考单元来进行闭包,通常是事件。

答案 2 :(得分:6)

this MSDN Blog article部分简化使用可变值中所述,您不再需要为lambdas使用ref单元格。 所以一般来说你根本不再需要它们。

答案 3 :(得分:4)

Brian的

This article可能会给出答案。

Mutables易于使用且高效(无包装),但无法在lambdas中捕获。可以捕获参考单元 ,但是冗长且效率较低(? - 不确定)。

答案 4 :(得分:3)

您可能需要查看wikibook中的Mutable Data部分。

为方便起见,这里有一些相关的引用:

  

经常使用mutable关键字   用记录类型来创建可变的   记录

     

可变变量有点   有限:变量无法访问   超出功能范围   他们被定义的地方。特别,   这意味着它不可能   引用子函数中的mutable   另一个功能。

     

参考细胞绕过一些   变量的局限性。事实上,参考   细胞是非常简单的数据类型   在记录中包含一个可变字段   类型。

     

因为ref cell被分配了   堆,它们可以共享   多功能