Как я могу гарантировать, что переполнение не произойдет в константных переменных? - PullRequest
1 голос
/ 13 апреля 2020

Я могу описать размер этой "круглой" гексгрид .. .. 1001 *

circular hex grid

.. только 1 значение n определено во время компиляции :

const GRID_RADIUS: usize = 3;

Следовательно, число ячеек в сетке также известно во время компиляции, поскольку оно равно (2n+1)^2-n*(n+1) (здесь 37).

Однако, следующее:

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

struct Cell;

struct Grid {
    cells: [Cell; N_CELLS],
}

Не компилируется:

error: any use of this value will cause an error
 --> src/main.rs:2:34
  |
2 | const N_CELLS: usize = ((2 * N + 1) ^ 2) - N * (N + 1);
  | -----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
  |                        |
  |                        attempt to subtract with overflow
  |
  = note: `#[deny(const_err)]` on by default

Я понимаю, что rustc беспокоится о том, что вычитание usize типов может привести к переполнению, но я могу гарантировать, что N_CELLS всегда будет положительным в этом случае.

Как я могу взять на себя ответственность за это и доверить rustc мне?

1 Ответ

5 голосов
/ 13 апреля 2020

Нет гарантии, что постоянные значения вычисляются во время компиляции. Компилятор знает , если значение переполнено, потому что он выполнил вычисление.

Я понимаю, что rustc беспокоится о том, что вычитание usize типов может привести к переполнению, но я могу гарантировать что N_CELLS всегда будет положительным в этом случае.

Как я могу взять на себя ответственность за это и заставить rustc довериться мне?

Вы не можете гарантировать это (и компилятор не должен вам доверять) потому что вы не правы . ^ означает XOR, а не «во власть». Компилятор выполнил ваш код и вычитал буквально ниже нуля, вызывая ошибку. Это не гипотетически:

((2 * n) ^ 2) = 4
n * (n + 1) = 12
4 - 12 = -8
fn main() {
    let n: usize = 3;
    let n_cells: usize = ((2 * n) ^ 2) - n * (n + 1);
}
thread 'main' panicked at 'attempt to subtract with overflow', src/main.rs:3:26

См. Также:

К сожалению, в настоящее время вы не можете использовать pow в константе:

const N: usize = 3;
const N_CELLS: usize = ((2 * N + 1).pow(2)) - N * (N + 1);
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
 --> src/lib.rs:2:24
  |
2 | const N_CELLS: usize = ((2 * N + 1).pow(2)) - N * (N + 1);
  |                        ^^^^^^^^^^^^^^^^^^^^

Вы должны будете расширить умножение самостоятельно:

const N_CELLS: usize = {
    let a = 2 * N + 1;
    let b = N * (N + 1);
    a * a - b
};
...