]> git.proxmox.com Git - rustc.git/blame - src/doc/book/casting-between-types.md
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / doc / book / casting-between-types.md
CommitLineData
92a42be0
SL
1% Casting Between Types
2
3Rust, with its focus on safety, provides two different ways of casting
4different types between each other. The first, `as`, is for safe casts.
5In contrast, `transmute` allows for arbitrary casting, and is one of the
6most dangerous features of Rust!
7
8# Coercion
9
10Coercion between types is implicit and has no syntax of its own, but can
11be spelled out with [`as`](#explicit-coercions).
12
13Coercion occurs in `let`, `const`, and `static` statements; in
14function call arguments; in field values in struct initialization; and in a
15function result.
16
17The most common case of coercion is removing mutability from a reference:
18
19 * `&mut T` to `&T`
54a0048b 20
92a42be0
SL
21An analogous conversion is to remove mutability from a
22[raw pointer](raw-pointers.md):
23
24 * `*mut T` to `*const T`
54a0048b 25
92a42be0
SL
26References can also be coerced to raw pointers:
27
28 * `&T` to `*const T`
29
30 * `&mut T` to `*mut T`
31
32Custom coercions may be defined using [`Deref`](deref-coercions.md).
33
34Coercion is transitive.
54a0048b 35
92a42be0
SL
36# `as`
37
38The `as` keyword does safe casting:
39
40```rust
41let x: i32 = 5;
42
43let y = x as i64;
44```
45
46There are three major categories of safe cast: explicit coercions, casts
47between numeric types, and pointer casts.
48
49Casting is not transitive: even if `e as U1 as U2` is a valid
50expression, `e as U2` is not necessarily so (in fact it will only be valid if
51`U1` coerces to `U2`).
52
53
54## Explicit coercions
55
56A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
57
58## Numeric casts
59
60A cast `e as U` is also valid in any of the following cases:
61
62 * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
63 * `e` is a C-like enum (with no data attached to the variants),
64 and `U` is an integer type; *enum-cast*
65 * `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast*
66 * `e` has type `u8` and `U` is `char`; *u8-char-cast*
54a0048b 67
92a42be0
SL
68For example
69
70```rust
71let one = true as u8;
72let at_sign = 64 as char;
73let two_hundred = -56i8 as u8;
74```
75
76The semantics of numeric casts are:
77
78* Casting between two integers of the same size (e.g. i32 -> u32) is a no-op
79* Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will
80 truncate
81* Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will
82 * zero-extend if the source is unsigned
83 * sign-extend if the source is signed
84* Casting from a float to an integer will round the float towards zero
85 * **[NOTE: currently this will cause Undefined Behavior if the rounded
86 value cannot be represented by the target integer type][float-int]**.
87 This includes Inf and NaN. This is a bug and will be fixed.
88* Casting from an integer to float will produce the floating point
89 representation of the integer, rounded if necessary (rounding strategy
90 unspecified)
91* Casting from an f32 to an f64 is perfect and lossless
92* Casting from an f64 to an f32 will produce the closest possible value
93 (rounding strategy unspecified)
94 * **[NOTE: currently this will cause Undefined Behavior if the value
95 is finite but larger or smaller than the largest or smallest finite
96 value representable by f32][float-float]**. This is a bug and will
97 be fixed.
98
99[float-int]: https://github.com/rust-lang/rust/issues/10184
100[float-float]: https://github.com/rust-lang/rust/issues/15536
54a0048b 101
92a42be0 102## Pointer casts
54a0048b 103
92a42be0
SL
104Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.md) to and
105from integers, and to cast between pointers to different types subject to
106some constraints. It is only unsafe to dereference the pointer:
107
108```rust
109let a = 300 as *const char; // a pointer to location 300
110let b = a as u32;
111```
112
113`e as U` is a valid pointer cast in any of the following cases:
114
115* `e` has type `*T`, `U` has type `*U_0`, and either `U_0: Sized` or
116 `unsize_kind(T) == unsize_kind(U_0)`; a *ptr-ptr-cast*
54a0048b 117
92a42be0
SL
118* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
119
120* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
121
122* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
123
124* `e` is a function pointer type and `U` has type `*T`,
125 while `T: Sized`; *fptr-ptr-cast*
126
127* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
128
129
130# `transmute`
131
132`as` only allows safe casting, and will for example reject an attempt to
133cast four bytes into a `u32`:
134
135```rust,ignore
136let a = [0u8, 0u8, 0u8, 0u8];
137
138let b = a as u32; // four eights makes 32
139```
140
141This errors with:
142
143```text
144error: non-scalar cast: `[u8; 4]` as `u32`
145let b = a as u32; // four eights makes 32
146 ^~~~~~~~
147```
148
149This is a ‘non-scalar cast’ because we have multiple values here: the four
150elements of the array. These kinds of casts are very dangerous, because they
151make assumptions about the way that multiple underlying structures are
152implemented. For this, we need something more dangerous.
153
154The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
155what it does is very simple, but very scary. It tells Rust to treat a value of
156one type as though it were another type. It does this regardless of the
9cc50fc6 157typechecking system, and completely trusts you.
92a42be0
SL
158
159[intrinsics]: intrinsics.html
160
161In our previous example, we know that an array of four `u8`s represents a `u32`
162properly, and so we want to do the cast. Using `transmute` instead of `as`,
163Rust lets us:
164
165```rust
166use std::mem;
167
168unsafe {
169 let a = [0u8, 0u8, 0u8, 0u8];
170
171 let b = mem::transmute::<[u8; 4], u32>(a);
172}
173```
174
175We have to wrap the operation in an `unsafe` block for this to compile
176successfully. Technically, only the `mem::transmute` call itself needs to be in
177the block, but it's nice in this case to enclose everything related, so you
178know where to look. In this case, the details about `a` are also important, and
179so they're in the block. You'll see code in either style, sometimes the context
180is too far away, and wrapping all of the code in `unsafe` isn't a great idea.
181
182While `transmute` does very little checking, it will at least make sure that
183the types are the same size. This errors:
184
185```rust,ignore
186use std::mem;
187
188unsafe {
189 let a = [0u8, 0u8, 0u8, 0u8];
190
191 let b = mem::transmute::<[u8; 4], u64>(a);
192}
193```
194
195with:
196
197```text
198error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
199(64 bits)
200```
201
202Other than that, you're on your own!