Rust 数组可以包含多少个元素?

9

这段代码给我报错了:

fn main() {
    let x = [0 as u64; std::u64::MAX as usize];
    println!("Hello, world! {}", std::u64::MAX);
}

error: the type `[u64; 18446744073709551615]` is too big for the current architecture
 --> src/main.rs:2:9
  |
2 |     let x = [0 as u64; std::u64::MAX as usize];
  |         ^

13
你是否拥有1.37万亿吉字节的内存?因为那是你需要为那个数组所需的容量。 - interjay
8
正如错误提示所示,限制在于“当前架构”,而不是 Rust 本身。默认的栈大小为 2 MB,因此只要运行试图实例化超过 2 百万个元素的数组的代码,就会导致堆栈溢出(实际上是 250,000 个 u64)。您将永远无法分配您尝试的那么多内存,即使您使用(例如)一个 Vec 将其放在堆上。 - Peter Hall
我认为这里的问题在于你正在指定操作系统将为数组保留的实际内存大小,而不是最大大小。如果您不知道编译时数组的长度,可以尝试使用Vec - Coder-256
@interjay,从技术上讲,你可能需要这么多的内存来托管这个数组。但实际上,使用虚拟内存技巧(比如直到实际需要时才初始化页面,或者交换,但是目前没有已知的大型存储设备可用于此),你可以拥有它。并且它会工作,直到它不再工作。显然,这不是“rust”的做事方式。 - user28434'mstep
4
@user28434 即使使用虚拟内存技巧,也无法声明这么大的数组,因为即使使用64位指针,也无法寻址。 - Jmb
1个回答

14

数组长度受 isize 类型限制,该类型为平台大小的整数:

isize 类型是带有与平台指针类型相同位数的有符号整数类型。对象和数组大小的理论上限是最大的 isize 值。这确保 isize 可用于计算指向对象或数组内部的指针之间的差异,并可以寻址对象中的每个字节以及结束后的一个字节。

  • 16 位平台:最大值为 215 - 1
  • 32 位平台:最大值为 231 - 1
  • 64 位平台:最大值为 263 - 1
fn main() {
    let x = [(); std::isize::MAX];
    println!("Hello, world! {}", x.len());
}

您的错误是因为当元素大小非零时,构建那么多元素的数组将需要大量的内存,超出了给定平台实际支持的范围。

一个数组的大小由元素大小乘以元素数量计算。您的数组具有u64类型(8字节)的元素,并尝试拥有264 - 1个元素,总共147.6艾字节。

在64位Linux上,使用Rust 1.38,最大大小似乎为247 - 1:

[0u8; (1usize << 47) - 1];

2
在64位Linux上,使用Rust 1.38,最大大小似乎是2⁴⁷ - 1:虽然您可以编译这样的程序,但它将立即在任何真实机器上发生段错误,因为那仍然是一兆字节的内存。 - mcarton
2
这个Nomicon章节提到了"As such we must limit all allocations to isize::MAX elements"。我认为还有一些更微妙的限制。该章节提到了很多关于分配限制的细节。 - Lukas Kalbertodt
5
值得一提的是,之所以使用2^47而不是2^48,是因为地址空间是不连续的,与isize/usize问题无关(只有在可以使用整个地址空间时才会成为问题)。规范地址 - trent
@Shepmaster 在最新版本的Rust(1.71.1)中,使用std::isize::MAX会导致编译时错误:let x = [(); std::isize::MAX]; | ^^^^^^^^^^^^^^^ 期望类型为 usize,但实际类型为 isize。根据您的选择,可以选择以下替代方案之一:let x : [(); 9223372036854775807] = [(); std::isize::MAX as usize];或者 let y : [(); 18446744073709551615] = [(); std::usize::MAX];` - imraklr

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