Привет, ЛОР. Начал изучать Rust, за плечами 10 лет разработки на Java/Kotlin, так что в теме не зеленый, но вопрос возник очень примитивный.
Смотрим книгу по типам данных, там написано следующее.
Let’s say you have a variable of type u8 that can hold values between 0 and 255. If you try to change the variable to a value outside that range, such as 256, integer overflow will occur, which can result in one of two behaviors. When you’re compiling in debug mode, Rust includes checks for integer overflow that cause your program to panic at runtime if this behavior occurs. Rust uses the term panicking when a program exits with an error; we’ll discuss panics in more depth in the “Unrecoverable Errors with panic!” section in Chapter 9.
When you’re compiling in release mode with the --release flag, Rust does not include checks for integer overflow that cause panics. Instead, if overflow occurs, Rust performs two’s complement wrapping. In short, values greater than the maximum value the type can hold “wrap around” to the minimum of the values the type can hold. In the case of a u8, the value 256 becomes 0, the value 257 becomes 1, and so on. The program won’t panic, but the variable will have a value that probably isn’t what you were expecting it to have. Relying on integer overflow’s wrapping behavior is considered an error.
Читая прямо и в лоб, если собираем в debug - упадем в panic, если в релизе - получим 0/1/2, в зависимости от того, насколько вышли за границы u8.
А теперь практика.
fn main() {
let mut number: u8 = 255;
number += 1;
}
Вот этот код не собирается, ни в debug, ни в release, ошибка компилятора следующая
error: this arithmetic operation will overflow
--> src/main.rs:3:5
|
3 | number += 1;
| ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
Однако, стоить добавить всего одну строчку к этому коду
fn main() {
let mut number: u8 = 255;
number += 1;
println!("The number is: {number}");
}
И поведение программы соответствует описанному в книге, собственно, вопрос: Почему вызов println! так влияет на это? В первом случае оно даже не собирается и overflow ловится на этапе компиляции, но стоит добавить println! и все начинает работать совсем иначе.