传递可变变量作为参数浪费内存?

时间:2017-09-30 18:56:41

标签: memory f# immutability mutable

我想知道使用可变变量是否会导致内存被浪费。

考虑以下两个示例,其输出(值abc)应相同:

// Example 1

let mutable mut = Map.empty

mut <- mut |> Map.add "A" 0
let fA (m: Map<string,int>) x = m.["A"] + x
let a = fA mut 0 // 0

mut <- mut |> Map.add "B" 1
let fB (m: Map<string,int>) x = m.["A"] + m.["B"] + x
let b = fB mut 0 // 1

mut <- mut |> Map.add "C" 2
let fC (m: Map<string,int>) x = m.["A"] + m.["B"] + m.["C"] + x
let c = fC mut 0 // 3

Example 1中,每个函数都使用一个可变参数,并且必须(我假设)复制该参数。 总共制作了三份。

// Example 2
let mutable mut = Map.empty

mut <- mut |> Map.add "A" 0
mut <- mut |> Map.add "B" 1
mut <- mut |> Map.add "C" 2

let fA (m: Map<string,int>) x = m.["A"] + x
let fB (m: Map<string,int>) x = m.["A"] + m.["B"] + x
let fC (m: Map<string,int>) x = m.["A"] + m.["B"] + m.["C"] + x

let immut = mut

let a = fA mut 0 // 0
let b = fB mut 0 // 1
let c = fC mut 0 // 3

Example 2中,每个函数都会复制相同的不可变参数。 据推测,编译器足够智能,在制作这些副本时不会使用任何额外的内存。对于每个副本,只能是指向原始对象的指针。

因此,尽管Example 1中复制的对象平均比Example 2中的不可变对象小,但Example 2中将使用更少的内存。

这种推理是否正确?

1 个答案:

答案 0 :(得分:3)

在您的示例中,Map<'K, 'V>值是不可变的,唯一可变的是您用来保持对mut值的当前实例的引用的引用Map<'K, 'V>。编译器不需要复制该值(我不认为F#编译器会在后面制作副本 - 除了值类型之外)。

这意味着你的两个例子几乎相同 - 唯一真正的区别在于,在例2中,你将一个包含更多值的地图传递给三个函数,因此查找可能会稍微长一些(但这是理论上的问题充其量)。

如果您使用可变数据结构(调整大小数组)和显式复制实现以下代码,则可能会出现您所暗示的问题:

let data = ResizeArray<string * int>()

data.Add("A", 0)
let f1 = 
  let lookup = dict data 
  fun x -> lookup.[x]

data.Add("B", 1)
let f2 = 
  let lookup = dict data 
  fun x -> lookup.[x]

f1 "A" // = 0
f1 "B" // error
f2 "A" // = 0
f2 "B" // = 1