-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of #24632 - steveklabnik:casting_guide, r=alexcrichton
Due to documenting `transmute`, addresses part of #12905
- Loading branch information
Showing
1 changed file
with
87 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,89 @@ | ||
% Casting Between Types | ||
|
||
Coming Soon | ||
Rust, with its focus on safety, provides two different ways of casting | ||
different types between each other. The first, `as`, is for safe casts. | ||
In contrast, `transmute` allows for arbitrary casting, and is one of the | ||
most dangerous features of Rust! | ||
|
||
# `as` | ||
|
||
The `as` keyword does basic casting: | ||
|
||
```rust | ||
let x: i32 = 5; | ||
|
||
let y = x as i64; | ||
``` | ||
|
||
It only allows certain kinds of casting, however: | ||
|
||
```rust,ignore | ||
let a = [0u8, 0u8, 0u8, 0u8]; | ||
let b = a as u32; // four eights makes 32 | ||
``` | ||
|
||
This errors with: | ||
|
||
```text | ||
error: non-scalar cast: `[u8; 4]` as `u32` | ||
let b = a as u32; // four eights makes 32 | ||
^~~~~~~~ | ||
``` | ||
|
||
It’s a ‘non-scalar cast’ because we have multiple values here: the four | ||
elements of the array. These kinds of casts are very dangerous, because they | ||
make assumptions about the way that multiple underlying strucutres are | ||
implemented. For this, we need something more dangerous. | ||
|
||
# `transmute` | ||
|
||
The `transmute` function is provided by a [compiler intrinsic][intrinsics], and | ||
what it does is very simple, but very scary. It tells Rust to treat a value of | ||
one type as though it were another type. It does this regardless of the | ||
typechecking system, and just completely trusts you. | ||
|
||
[intrinsic]: intrinsics.html | ||
|
||
In our previous example, we know that an array of four `u8`s represents a `u32` | ||
properly, and so we want to do the cast. Using `transmute` instead of `as`, | ||
Rust lets us: | ||
|
||
```rust | ||
use std::mem; | ||
|
||
unsafe { | ||
let a = [0u8, 0u8, 0u8, 0u8]; | ||
|
||
let b = mem::transmute::<[u8; 4], u32>(a); | ||
} | ||
``` | ||
|
||
We have to wrap the operation in an `unsafe` block, but this will compile | ||
successfully. Technically, only the `mem::transmute` call itself needs to be in | ||
the block, but it's nice in this case to enclose everything related, so you | ||
know where to look. In this case, the details about `a` are also important, and | ||
so they're in the block. You'll see code in either style, sometimes the context | ||
is too far away, and wrapping all of the code in `unsafe` isn't a great idea. | ||
|
||
While `transmute` does very little checking, it will at least make sure that | ||
the types are the same size. This errors: | ||
|
||
```rust,ignore | ||
use std::mem; | ||
unsafe { | ||
let a = [0u8, 0u8, 0u8, 0u8]; | ||
let b = mem::transmute::<[u8; 4], u64>(a); | ||
} | ||
``` | ||
|
||
with: | ||
|
||
```text | ||
error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64 | ||
(64 bits) | ||
``` | ||
|
||
Other than that, you're on your own! |