Rust: как преобразовать знаковый целочисленный тип в больший знаковый целочисленный тип * без расширения знака * - PullRequest
1 голос
/ 28 мая 2020

Предположим, у нас есть i8, которое мы хотим преобразовать в i16 без расширения знака .

Мы не можем выполнить простое преобразование as, так как это будет означать расширение.

println!("{:b}", -128i8); // 10000000 <- we want this zero-extended in an i16.
println!("{:b}", -128i8 as i16);  // 1111111110000000 sign extended :(

Мы не можем преобразовать, потому что типы имеют разный размер:

println!("{:b}", unsafe {mem::transmute::<_, i16>(128i8)});
// ^ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types :(

Лучшее, что я придумал, - это следующая запутанная цепочка литья:

println!("{:b}", -128i8 as u8 as u16 as i16); // 10000000 :), but :( because convoluted.

Промежуточное приведение к u8 означает, что приведение к u16 будет расширяться нулем вместо расширения знака, тогда приведение от u16 к i16 нормально, поскольку типы одинакового размера, и расширение не требуется.

Но должен ли быть лучший способ? Есть?

1 Ответ

4 голосов
/ 28 мая 2020

Имея в виду, что в этом случае (печать битов числа) вы можете просто выполнить беззнаковое преобразование.

Однако в целом Rust не очень любит выполнять неявные преобразования, но вы всегда можете написать

let n : i8 = -128;
let m : i32 = n as u8 as i32;

В общем, вы не можете стать лучше этого, поскольку двойное приведение является обычным явлением в таких полях, как изменение типов указателей. Также подумайте о том, чтобы не использовать unsafe, если выполняемая вами операция может быть выполнена безопасно без недостатков (кроме, возможно, легкого запаха кода).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...