Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I cast a `u32` to `char`?

Tags:

rust

I'm trying to learn Rust and I got caught up thinking about how chars are 4 bytes wide. I can cast a char to a u32 and it works out (they are both 4 bytes wide), however, when I cast from a u32 to a char, Rust complains:

fn main() {
    let pizza_hex: u32 = 0x1f355;
    let pizza: char = '🍕'; // (pizza char: http://www.fileformat.info/info/unicode/char/1f355/index.htm)

    // pizza as hex = 1f355
    println!("pizza as hex = {:x}", pizza as u32);

    // size of pizza = 4
    println!("size of pizza = {}", std::mem::size_of_val(&pizza));

    // This doesn't work super well
    println!("{} == {}", pizza_hex as char, pizza);
}
error[E0604]: only `u8` can be cast as `char`, not `u32`
  --> src/main.rs:12:26
   |
12 |     println!("{} == {}", pizza_hex as char, pizza);
   |                          ^^^^^^^^^^^^^^^^^

Any ideas why?

like image 844
Michael Tang Avatar asked Sep 29 '14 20:09

Michael Tang


1 Answers

Every char is a valid u32 value, but not every u32 value is a valid char.

The property of chars holding valid Unicode codepoints factors into memory safety:

Behavior considered undefined

  • Invalid values in primitive types, even in private fields and locals:
    • A value in a char which is a surrogate or above char::MAX.

To convert a u32 to a char at runtime, try this:

if let Some(pizza_from_hex) = std::char::from_u32(pizza_hex) {
    println!("{} == {}", pizza_from_hex, pizza);
}

If you just don't want creepy Unicode glyphs in your character literals, you can use Unicode escape sequences:

let pizza_from_hex = '\u{01f355}';

println!("{} == {}", pizza_from_hex, pizza);
like image 181
ben Avatar answered Dec 07 '22 00:12

ben