Skip to content

Commit fb57ba0

Browse files
committed
Rollup merge of #24632 - steveklabnik:casting_guide, r=alexcrichton
Due to documenting `transmute`, addresses part of #12905
2 parents e8db262 + 9a65045 commit fb57ba0

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

src/doc/trpl/casting-between-types.md

+87-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,89 @@
11
% Casting Between Types
22

3-
Coming Soon
3+
Rust, with its focus on safety, provides two different ways of casting
4+
different types between each other. The first, `as`, is for safe casts.
5+
In contrast, `transmute` allows for arbitrary casting, and is one of the
6+
most dangerous features of Rust!
7+
8+
# `as`
9+
10+
The `as` keyword does basic casting:
11+
12+
```rust
13+
let x: i32 = 5;
14+
15+
let y = x as i64;
16+
```
17+
18+
It only allows certain kinds of casting, however:
19+
20+
```rust,ignore
21+
let a = [0u8, 0u8, 0u8, 0u8];
22+
23+
let b = a as u32; // four eights makes 32
24+
```
25+
26+
This errors with:
27+
28+
```text
29+
error: non-scalar cast: `[u8; 4]` as `u32`
30+
let b = a as u32; // four eights makes 32
31+
^~~~~~~~
32+
```
33+
34+
It’s a ‘non-scalar cast’ because we have multiple values here: the four
35+
elements of the array. These kinds of casts are very dangerous, because they
36+
make assumptions about the way that multiple underlying strucutres are
37+
implemented. For this, we need something more dangerous.
38+
39+
# `transmute`
40+
41+
The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
42+
what it does is very simple, but very scary. It tells Rust to treat a value of
43+
one type as though it were another type. It does this regardless of the
44+
typechecking system, and just completely trusts you.
45+
46+
[intrinsic]: intrinsics.html
47+
48+
In our previous example, we know that an array of four `u8`s represents a `u32`
49+
properly, and so we want to do the cast. Using `transmute` instead of `as`,
50+
Rust lets us:
51+
52+
```rust
53+
use std::mem;
54+
55+
unsafe {
56+
let a = [0u8, 0u8, 0u8, 0u8];
57+
58+
let b = mem::transmute::<[u8; 4], u32>(a);
59+
}
60+
```
61+
62+
We have to wrap the operation in an `unsafe` block, but this will compile
63+
successfully. Technically, only the `mem::transmute` call itself needs to be in
64+
the block, but it's nice in this case to enclose everything related, so you
65+
know where to look. In this case, the details about `a` are also important, and
66+
so they're in the block. You'll see code in either style, sometimes the context
67+
is too far away, and wrapping all of the code in `unsafe` isn't a great idea.
68+
69+
While `transmute` does very little checking, it will at least make sure that
70+
the types are the same size. This errors:
71+
72+
```rust,ignore
73+
use std::mem;
74+
75+
unsafe {
76+
let a = [0u8, 0u8, 0u8, 0u8];
77+
78+
let b = mem::transmute::<[u8; 4], u64>(a);
79+
}
80+
```
81+
82+
with:
83+
84+
```text
85+
error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64
86+
(64 bits)
87+
```
88+
89+
Other than that, you're on your own!

0 commit comments

Comments
 (0)