* Render the book in PDF using `pandoc` and LaTeX. * Fix installs. * Go the apt-get route * Another attempt * Avoid installing twice. * Re-order. * Add more packages. * Minimise deps. Fix link checker. * Missing package. * Missing package. * Missing package. * More packages. * Missing package. * Missing package. * More packages... * Remove. * Fix link checker. * Fix link checker. * Fix path. * Add subtitle. * Avoid running over the right margin. * Avoid running over the right margin. * Formatting
2.9 KiB
Conversions, pt. 1
We’ve repeated over and over again that Rust won’t perform implicit
type conversions for integers.
How do you perform explicit conversions then?
as
You can use the as operator to convert between integer
types.
as conversions are infallible.
For example:
let a: u32 = 10;
// Cast `a` into the `u64` type
let b = a as u64;
// You can use `_` as the target type
// if it can be correctly inferred
// by the compiler. For example:
let c: u64 = a as _;The semantics of this conversion are what you expect: all
u32 values are valid u64 values.
Truncation
Things get more interesting if we go in the opposite direction:
// A number that's too big
// to fit into a `u8`
let a: u16 = 255 + 1;
let b = a as u8;This program will run without issues, because as
conversions are infallible. But what is the value of b?
When going from a larger integer type to a smaller, the Rust compiler
will perform a truncation.
To understand what happens, let’s start by looking at how
256u16 is represented in memory, as a sequence of bits:
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
| | |
+---------------+---------------+
First 8 bits Last 8 bits
When converting to a u8, the Rust compiler will keep the
last 8 bits of a u16 memory representation:
0 0 0 0 0 0 0 0
| |
+---------------+
Last 8 bits
Hence 256 as u8 is equal to 0. That’s… not
ideal, in most scenarios.
In fact, the Rust compiler will actively try to stop you if it sees you
trying to cast a literal value which will result in a truncation:
error: literal out of range for `i8`
|
4 | let a = 255 as i8;
| ^^^
|
= note: the literal `255` does not fit into the type `i8`
whose range is `-128..=127`
= help: consider using the type `u8` instead
= note: `#[deny(overflowing_literals)]` on by default
Recommendation
As a rule of thumb, be quite careful with as
casting.
Use it exclusively for going from a smaller type to a larger
type. To convert from a larger to smaller integer type, rely on the fallible conversion
machinery that we’ll explore later in the course.
Limitations
Surprising behaviour is not the only downside of as
casting. It is also fairly limited: you can only rely on as
casting for primitive types and a few other special cases.
When working with composite types, you’ll have to rely on different
conversion mechanisms (fallible and infallible), which we’ll explore
later on.
Further reading
- Check out Rust’s
official reference to learn the precise behaviour of
ascasting for each source/target combination, as well as the exhaustive list of allowed conversions.