如何保证 const 变量不会发生溢出?

iag*_*ito 1 compiler-errors constants integer-overflow unsigned-integer rust

我可以描述这个“圆形”六边形网格的尺寸..

圆形六角网格

..n在编译时只定义了1 个值:

const GRID_RADIUS: usize = 3;
Run Code Online (Sandbox Code Playgroud)

因此,网格中的单元格数量在编译时也是已知的,因为它是(2n+1)^2-n*(n+1)(此处为 37)。

但是,以下内容:

const GRID_RADIUS: usize = 3;
Run Code Online (Sandbox Code Playgroud)

不编译:

const N: usize = 3;
const N_CELLS: usize = ((2 * N + 1) ^ 2) - N * (N + 1);

struct Cell;

struct Grid {
    cells: [Cell; N_CELLS],
}
Run Code Online (Sandbox Code Playgroud)

我知道rustc担心减去usize类型可能会导致溢出,但我可以保证N_CELLS在这种情况下总是积极的。

我怎么能为此承担责任并rustc信任我?

She*_*ter 5

不能保证 - 在编译时评估常量值。编译器知道某个值是否因为它执行了计算而溢出。

我知道rustc担心减去usize类型可能会导致溢出,但我可以保证N_CELLS在这种情况下总是积极的。

我怎么能为此承担责任并rustc信任我?

您不能保证这一点(并且编译器不应该信任您),因为您不正确^意思是异或,而不是“to the power of”。编译器执行您的代码并逐字地减去零以下,从而触发错误。这不是假设:

((2 * n) ^ 2) = 4
n * (n + 1) = 12
4 - 12 = -8
Run Code Online (Sandbox Code Playgroud)
fn main() {
    let n: usize = 3;
    let n_cells: usize = ((2 * n) ^ 2) - n * (n + 1);
}
Run Code Online (Sandbox Code Playgroud)
fn main() {
    let n: usize = 3;
    let n_cells: usize = ((2 * n) ^ 2) - n * (n + 1);
}
Run Code Online (Sandbox Code Playgroud)

事实上,多亏了这个问题,Rust 现在显示了导致溢出的值,希望能更清楚地说明原来的错误:

thread 'main' panicked at 'attempt to subtract with overflow', src/main.rs:3:26
Run Code Online (Sandbox Code Playgroud)

也可以看看:

不幸的是,您目前不能pow在常量中使用:

const N: usize = 3;
const N_CELLS: usize = ((2 * N + 1).pow(2)) - N * (N + 1);
Run Code Online (Sandbox Code Playgroud)
 --> src/lib.rs:2:24
  |
2 | const N_CELLS: usize = ((2 * N + 1) ^ 2) - N * (N + 1);
  | -----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
  |                        |
  |                        attempt to compute `5_usize - 12_usize` which would overflow
  |
  = note: `#[deny(const_err)]` on by default
Run Code Online (Sandbox Code Playgroud)

您必须自己扩展乘法:

const N_CELLS: usize = {
    let a = 2 * N + 1;
    let b = N * (N + 1);
    a * a - b
};
Run Code Online (Sandbox Code Playgroud)