OCaml中Array.create的奇怪行为

4

我是OCaml的新手。在使用数组编码时,我遇到了一个我无法理解的问题。
以下是代码:

let a = Array.create 5 (Array.create 5 0);
a.(0).(1) <- 1

我只是想将1分配给a[0][1],但接着发生了一些事情:第一列中的所有元素都被赋值。也就是说,在上面的代码执行后,a[0][1]、a[1][1]、a[2][1]、a[3][1]和a[4][1]都等于1。
如果我使用以下方式创建数组:

Array.make_matrix 5 5 0

everything is fine.

My environment:

Ubuntu 13.10
Ocaml 4.01.0
open Core.Std 
3个回答

7

Array.create存在一个常见陷阱。当你的数组元素是装箱类型时,请使用Array.init代替。

Array.create初始化数组元素时使用相同的值:如果该值是装箱类型,则使用相同的指针。在您的情况下,所有元素a.(i)都指向由Array.create 5 0创建的同一数组。

正确的代码应该是

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

这将创建5个单独的数组。
你应该查看这个问题/答案:Ocaml - 访问记录数组中的组件

我认为盒装性与此无关。这更多是可变性/不可变性的问题。 - Ben Millwood
不,Boxedness 在这里非常重要。Array.create 5 0 创建一个包含 5 个 0 的数组,因为 0 是 unboxed。当 p 是指针时,Array.create 5 p 会创建 5 个指向相同对象的指针,通常这不是您想要的。 - camlspotter

4

您只调用了Array.create两次,因此只创建了两个数组 -- 一个数组的所有元素都指向另一个数组。

Array.create创建一个数组,并将每个元素设置为给定值的副本。因此就好像您这样做:

let x = Array.create 5 0;
let a = Array.create 5 <some dummy value>;
a.(0) <- x;
a.(1) <- x;
a.(2) <- x;
a.(3) <- x;
a.(4) <- x;

看到问题了吗?所有五个元素都设置为指向同一个数组的指针。
请注意,OCaml中的所有类型基本上都是引用类型。(技术上讲,int和一些较小的类型,比如char和bool,以及所有无参数构造函数的代数数据类型,都被实现为值类型。但是,值类型在语义上与不可变的引用类型相当,除了物理相等性。因此,为简单起见,您可以将所有类型视为引用类型。)

2

仅供参考:

这里是数组(Array)的文档:http://caml.inria.fr/pub/docs/manual-ocaml/libref/Array.html

val make : int -> 'a -> 'a array
函数 Array.make n x 返回一个长度为n的新数组,初始值均为x。
新数组所有元素在物理上都等于x(即使用“==”判断相等),因此,如果x是可变的,则会被所有数组元素共享, 通过修改数组中一个元素来修改x将同时修改所有其他元素。
如果n < 0或n > Sys.max_array_length,则引发Invalid_argument异常。 如果x的值为浮点数,则最大大小仅为Sys.max_array_length / 2。

val create : int -> 'a -> 'a array
已弃用。**Array.create是Array.make的别名**。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接