【问题标题】:Passing mutable variables as arguments wastes memory?将可变变量作为参数传递会浪费内存?
【发布时间】:2018-03-12 09:01:13
【问题描述】:

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

考虑以下两个示例,其输出(值a、b 和c)应该相同:

// 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 中将使用更少的内存。

这个推理正确吗?

【问题讨论】:

  • 不,没有任何东西被复制。您将引用的可变性与引用指向的数据结构的可变性混淆了。

标签: memory f# immutability mutable


【解决方案1】:

在您的示例中,Map&lt;'K, 'V&gt; 值是不可变的,唯一可变的是引用 mut,您使用它来保持对 Map&lt;'K, 'V&gt; 值的当前实例的引用。编译器不需要复制该值(我认为 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 2015-09-22
    • 2018-05-23
    • 2018-05-25
    • 2018-02-17
    • 1970-01-01
    相关资源
    最近更新 更多