使用Array.create和Array.init创建的数组中的行为不一致

时间:2011-03-01 06:08:05

标签: arrays f#

let a = Array.create 3 (Array.create 3 0)
let b = Array.init 3 (fun _ -> Array.init 3 (fun _ -> 0))

这两个数组都有签名int [] []和初始值[| [| 0; 0; 0 |]; [| 0; 0; 0 |]; [| 0; 0; 0 |] |。]

然而:

a.[0].[0] <- 3
b.[0].[0] <- 3

产生不同的结果:

a: [|[|3; 0; 0|]; [|3; 0; 0|]; [|3; 0; 0|]|]
b: [|[|3; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]|]

b的结果是我对两者的期望。

对我来说,相同的签名应该以相同的方式行事似乎是合乎逻辑的。谁能告诉我我错过了什么?

3 个答案:

答案 0 :(得分:3)

在第一个版本中,(Array.create 3 0)在作为参数传递之前被计算,因此数组的所有单元格都获得相同的值。 数组是引用类型,因此实际上所有单元都是相同的。

答案 1 :(得分:3)

Array.create的第二个参数是一个奇异值,用于初始化数组中的每个插槽。即,请考虑以下事项:

let a =
    let v = Array.create 3 0
    Array.create 3 v

v存储在a的所有3个广告位中,因此修改a中的任何元素都会影响所有3个广告位。

编辑:还要考虑逻辑上的等同性:

let b =
    let v = Array.create 3 0
    Array.init 3 (fun _ -> v)

答案 2 :(得分:3)

  

对我来说,相同的签名应该以相同的方式行事似乎是合乎逻辑的。谁能告诉我我错过了什么?

<强>共享

使用Array.create会生成共享相同值的元素数组。使用Array.init调用函数来创建每个元素的值。

因此,这会分配两个数组:

let a = Array.create 3 (Array.create 3 0)

而这会分配四个数组:

let b = Array.init 3 (fun _ -> Array.init 3 (fun _ -> 0))

你可能更愿意用数组文字来思考它,前者相当于:

let xs = [|0;0;0|]
[|xs;xs;xs|]

而后者相当于:

let xs = [|0;0;0|]
let ys = [|0;0;0|]
let zs = [|0;0;0|]
[|xs;ys;zs|]