]>
Commit | Line | Data |
---|---|---|
2c00a5a8 XL |
1 | # Casting |
2 | ||
3 | Rust provides no implicit type conversion (coercion) between primitive types. | |
4 | But, explicit type conversion (casting) can be performed using the `as` keyword. | |
5 | ||
6 | Rules for converting between integral types follow C conventions generally, | |
7 | except in cases where C has undefined behavior. The behavior of all casts | |
8 | between integral types is well defined in Rust. | |
9 | ||
10 | ```rust,editable,ignore,mdbook-runnable | |
11 | // Suppress all warnings from casts which overflow. | |
12 | #![allow(overflowing_literals)] | |
13 | ||
14 | fn main() { | |
15 | let decimal = 65.4321_f32; | |
16 | ||
17 | // Error! No implicit conversion | |
18 | let integer: u8 = decimal; | |
19 | // FIXME ^ Comment out this line | |
20 | ||
21 | // Explicit conversion | |
22 | let integer = decimal as u8; | |
23 | let character = integer as char; | |
24 | ||
cdc7bbd5 XL |
25 | // Error! There are limitations in conversion rules. |
26 | // A float cannot be directly converted to a char. | |
ba9703b0 XL |
27 | let character = decimal as char; |
28 | // FIXME ^ Comment out this line | |
29 | ||
2c00a5a8 XL |
30 | println!("Casting: {} -> {} -> {}", decimal, integer, character); |
31 | ||
32 | // when casting any value to an unsigned type, T, | |
ba9703b0 | 33 | // T::MAX + 1 is added or subtracted until the value |
2c00a5a8 XL |
34 | // fits into the new type |
35 | ||
36 | // 1000 already fits in a u16 | |
37 | println!("1000 as a u16 is: {}", 1000 as u16); | |
38 | ||
39 | // 1000 - 256 - 256 - 256 = 232 | |
40 | // Under the hood, the first 8 least significant bits (LSB) are kept, | |
41 | // while the rest towards the most significant bit (MSB) get truncated. | |
42 | println!("1000 as a u8 is : {}", 1000 as u8); | |
43 | // -1 + 256 = 255 | |
44 | println!(" -1 as a u8 is : {}", (-1i8) as u8); | |
45 | ||
46 | // For positive numbers, this is the same as the modulus | |
47 | println!("1000 mod 256 is : {}", 1000 % 256); | |
48 | ||
49 | // When casting to a signed type, the (bitwise) result is the same as | |
50 | // first casting to the corresponding unsigned type. If the most significant | |
51 | // bit of that value is 1, then the value is negative. | |
52 | ||
53 | // Unless it already fits, of course. | |
54 | println!(" 128 as a i16 is: {}", 128 as i16); | |
04454e1e FG |
55 | |
56 | // 128 as u8 -> -128, whose two's complement in eight bits is: | |
2c00a5a8 XL |
57 | println!(" 128 as a i8 is : {}", 128 as i8); |
58 | ||
59 | // repeating the example above | |
60 | // 1000 as u8 -> 232 | |
61 | println!("1000 as a u8 is : {}", 1000 as u8); | |
62 | // and the two's complement of 232 is -24 | |
63 | println!(" 232 as a i8 is : {}", 232 as i8); | |
29967ef6 | 64 | |
cdc7bbd5 XL |
65 | // Since Rust 1.45, the `as` keyword performs a *saturating cast* |
66 | // when casting from float to int. If the floating point value exceeds | |
67 | // the upper bound or is less than the lower bound, the returned value | |
68 | // will be equal to the bound crossed. | |
29967ef6 XL |
69 | |
70 | // 300.0 is 255 | |
71 | println!("300.0 is {}", 300.0_f32 as u8); | |
72 | // -100.0 as u8 is 0 | |
73 | println!("-100.0 as u8 is {}", -100.0_f32 as u8); | |
74 | // nan as u8 is 0 | |
75 | println!("nan as u8 is {}", f32::NAN as u8); | |
76 | ||
cdc7bbd5 XL |
77 | // This behavior incurs a small runtime cost and can be avoided |
78 | // with unsafe methods, however the results might overflow and | |
79 | // return **unsound values**. Use these methods wisely: | |
29967ef6 XL |
80 | unsafe { |
81 | // 300.0 is 44 | |
82 | println!("300.0 is {}", 300.0_f32.to_int_unchecked::<u8>()); | |
83 | // -100.0 as u8 is 156 | |
84 | println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::<u8>()); | |
85 | // nan as u8 is 0 | |
86 | println!("nan as u8 is {}", f32::NAN.to_int_unchecked::<u8>()); | |
87 | } | |
2c00a5a8 XL |
88 | } |
89 | ``` |