我们先说Array{T}(undef, dims)Array{T,N}(undef, dims)。这两个函数都是用来构造未初始化的 N 维数组的。其中的T依然代表元素类型,N依然代表维数。

    undef是一个常量,它代表着单例类型UndefInitializer的唯一值。所谓的单例类型,是指有且仅有一个实例的类型。无论我们实例化这种类型多少次,都只会得到同一个值,即该类型的唯一值。UndefInitializer类型专用于数组的初始化,其值表达的含义是创建一个未初始化的数组。或者说它表达的是,上述构造函数的调用者不想向这个数组填充任何的元素值。这时,Julia 会在该数组的所有元素位置上填充随机值。

    我们在前面讲了,数组类型的字面量上不会体现出数组在各个维度上的元素数量。然而,这些数量却是构造一个多维数组时必须要确定的信息。注意,对于多维数组,我们所说的在某个维度上的元素指的是可能一个个元素值,也可能是一个个低维数组。这在后面会有更详细的解释。

    这里的参数dims的作用正是表示数组在各个维度上的元素数量。更确切地说,它表示的是各个维度的长度。dims是 dimensions 的缩写。它的值可以是一个包含了若干个整数的元组值,也可以是若干个由英文逗号分隔的整数值。不过后者只在三维及以下的数组构造中才有效。下面是一个例子:

    请注意,回显内容中表示的是一个4×3×2的三维数组。还记得吗?我们可以把三维数组比喻成一座停车楼。那么上面这个三维数组就相当于一个有 2 层的停车楼。现在,你要带着这个想象跟我一起理解它的展示格式。

    图 9-2 4×3×2的三维数组的示意

    回显内容的第一行反映了我们构造数组时给予的信息。第二行中的[:, :, 1]指的是在第三个维度上的第 1 个低维数组(即二维数组),相当于停车楼的上一层。你也可以把[:, :, 1]看成一个特殊的数组,其中的每一个元素的值都用于代表上述三维数组在对应维度上的某个低维数组。这个特殊的数组中的前两个元素都由英文冒号:占位,相当于选择了对应维度上的所有低维数组。而其中的最后一个元素值是1,代表的正是上述三维数组中的第 1 个二维数组。由此,在它下面才展示了对应的二维数组中的所有元素值,相当于俯瞰停车楼的上一层。

    又由于上述三维数组在第三个维度上的长度是 2,所以才有了再下面的[:, :, 2],以及与它对应的又一个4×3的二维数组,相当于停车楼的下一层。

    让我们再来构造一个四维数组:

    四维数组可能会挑战到你的空间想象力。但有了前面的解释,这个四维数组的展示格式就应该容易理解一些了。这个四维数组由 2 个4×3×2的三维数组拼接而成,而这 2 个三维数组又分别由 2 个4×3的二维数组拼接而成。所以,[:, :, 1, 1]指的就是,这个四维数组中的第 1 个三维数组中的第 1 个二维数组。而[:, :, 2, 1]指的则是,这个四维数组中的第 1 个三维数组中的第 2 个二维数组。以此类推。紧挨在它们下面的那几行内容展示的就是对应的二维数组。你明白了吗?你可以再花一些时间思考一下。

    为什么 Julia 会这样展示多维数组呢?这主要是因为,我们在平面(如屏幕、纸张等)之上最多只能铺开二维的数组。虽然我们也可以在纸上画出三维的物体(如六面体、球体等),但那终归只是一种视觉上的效果。而且,那些物体只能被当作图形来看待,很难完全用普通的文本直观地展示出来。即使我们生活在三维的世界里,可所用的文字和语言都只是二维的。这也是我们不容易理解四维以及更多维数的原因。总之,Julia 在用二维的方式展示多维数组。它把多维数组拆分成了一个个二维数组,并以普通文本的形式摆在我们面前。

    言归正传。上例调用的是Array{T,N}(undef, dims)。这时我们需要注意,替代N的那个整数值一定要等同于替换掉dims的那个元组值的长度(或者替换掉dims的那些整数值的数量),否则 Julia 就会立即报错。因为两边给定的数组维数不一致。

    在前面,我们传给数组构造函数的第一个参数值一直是undef。但这只是初始化元素值的一种选项而已。我们还可以选择nothing或作为这个参数的值。但前提是,该数组的元素类型必须是nothingmissing的类型的超类型。

    nothingmissing也都是常量,其含义同样比较特殊。我们在前面的章节中对它们都做过解释。nothing代表着单例类型Nothing的唯一值,它的含义是“此处没有值”。而missing则代表单例类型Missing的唯一值,它的含义是“此处的值是缺失的”。

    可以看到,如果我们传给数组构造函数的第一个参数值是nothing,那么此次被创建出的数组的所有元素值就都会是nothing。若传入missing的话也是类似的。

    除了上面讲的构造函数,Julia 还提供了另外的一些可以创建多维数组的函数。比如,函数zeros可以创建元素值全为零值的数组。示例如下:

    zeros函数的第一个参数的名称是T,代表元素类型。这个参数是可选的,如果我们选择不为它传入值,那么其值就是缺省的Float64。该函数的第二个参数的名称是dims,与前述的构造函数中的dims含义相同。

    注意,这个函数的第一个参数值通常只能是一个数值类型。更具体地说,它可以是任意的布尔类型、整数类型、浮点数类型、复数类型,以及有理数类型。另外,对于不同的数值类型,其零值也是不同的。所谓的零值,就是用来表示0的值。比如,UInt8类型的零值是0x00Complex类型的零值是0+0im,类型的零值是0//1,等等。

    与之类似,ones函数可以创建元素值全为1的数组。其参数的定义与zeros函数的参数定义相同。仍要注意,不同的数值类型表示1的方式也不同。

    还有一个名叫fill的函数,它有两个参数:x‌和dims。参数x代表的值将会被填充到新数组的所有元素位置上。显然,新数组的元素类型由x决定。与前面一样,新数组的维数和大小仍由dims决定。下面是一个示例:

    另外,函数truesfalses也很常用。它们都只有一个名为dims的参数。trues函数用于创建元素值全为true的数组,而falses函数则用于创建元素值全为false的数组。注意,它们创建的数组的类型并不是Array,而是BitArray

    以上就是我们构造数组值的时候经常会用到的函数。当然,还有一些函数也可以被用来构造数组值,如函数randrandncollectsimilar、等。不过,这些函数在功能上就没有那么的纯粹了。