]> git.lizzy.rs Git - rust.git/blob - src/doc/tarpl/casts.md
cb12ffe8d21453a21c06ea2c14f8c7f7d5c52bc2
[rust.git] / src / doc / tarpl / casts.md
1 % Casts
2
3 Casts are a superset of coercions: every coercion can be explicitly
4 invoked via a cast. However some conversions *require* a cast.
5 While coercions are pervasive and largely harmless, these "true casts"
6 are rare and potentially dangerous. As such, casts must be explicitly invoked
7 using the `as` keyword: `expr as Type`.
8
9 True casts generally revolve around raw pointers and the primitive numeric
10 types. Even though they're dangerous, these casts are *infallible* at runtime.
11 If a cast triggers some subtle corner case no indication will be given that
12 this occurred. The cast will simply succeed. That said, casts must be valid
13 at the type level, or else they will be prevented statically. For instance,
14 `7u8 as bool` will not compile.
15
16 That said, casts aren't `unsafe` because they generally can't violate memory
17 safety *on their own*. For instance, converting an integer to a raw pointer can
18 very easily lead to terrible things. However the act of creating the pointer
19 itself is safe, because actually using a raw pointer is already marked as
20 `unsafe`.
21
22 Here's an exhaustive list of all the true casts. For brevity, we will use `*`
23 to denote either a `*const` or `*mut`, and `integer` to denote any integral
24 primitive:
25
26  * `*T as *U` where `T, U: Sized`
27  * `*T as *U` TODO: explain unsized situation
28  * `*T as integer`
29  * `integer as *T`
30  * `number as number`
31  * `C-like-enum as integer`
32  * `bool as integer`
33  * `char as integer`
34  * `u8 as char`
35  * `&[T; n] as *const T`
36  * `fn as *T` where `T: Sized`
37  * `fn as integer`
38
39 Note that lengths are not adjusted when casting raw slices -
40 `*const [u16] as *const [u8]` creates a slice that only includes
41 half of the original memory.
42
43 Casting is not transitive, that is, even if `e as U1 as U2` is a valid
44 expression, `e as U2` is not necessarily so.
45
46 For numeric casts, there are quite a few cases to consider:
47
48 * casting between two integers of the same size (e.g. i32 -> u32) is a no-op
49 * casting from a larger integer to a smaller integer (e.g. u32 -> u8) will
50   truncate
51 * casting from a smaller integer to a larger integer (e.g. u8 -> u32) will
52     * zero-extend if the source is unsigned
53     * sign-extend if the source is signed
54 * casting from a float to an integer will round the float towards zero
55     * **[NOTE: currently this will cause Undefined Behaviour if the rounded
56       value cannot be represented by the target integer type][float-int]**.
57       This includes Inf and NaN. This is a bug and will be fixed.
58 * casting from an integer to float will produce the floating point
59   representation of the integer, rounded if necessary (rounding strategy
60   unspecified)
61 * casting from an f32 to an f64 is perfect and lossless
62 * casting from an f64 to an f32 will produce the closest possible value
63   (rounding strategy unspecified)
64     * **[NOTE: currently this will cause Undefined Behaviour if the value
65       is finite but larger or smaller than the largest or smallest finite
66       value representable by f32][float-float]**. This is a bug and will
67       be fixed.
68
69
70 [float-int]: https://github.com/rust-lang/rust/issues/10184
71 [float-float]: https://github.com/rust-lang/rust/issues/15536