1 % Casting Between Types
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!
10 Coercion between types is implicit and has no syntax of its own, but can
11 be spelled out with [`as`](#explicit-coercions).
13 Coercion occurs in `let`, `const`, and `static` statements; in
14 function call arguments; in field values in struct initialization; and in a
17 The most common case of coercion is removing mutability from a reference:
21 An analogous conversion is to remove mutability from a
22 [raw pointer](raw-pointers.md):
24 * `*mut T` to `*const T`
26 References can also be coerced to raw pointers:
30 * `&mut T` to `*mut T`
32 Custom coercions may be defined using [`Deref`](deref-coercions.md).
34 Coercion is transitive.
38 The `as` keyword does safe casting:
46 There are three major categories of safe cast: explicit coercions, casts
47 between numeric types, and pointer casts.
49 Casting is not transitive: even if `e as U1 as U2` is a valid
50 expression, `e as U2` is not necessarily so (in fact it will only be valid if
51 `U1` coerces to `U2`).
56 A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
60 A cast `e as U` is also valid in any of the following cases:
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*
72 let at_sign = 64 as char;
73 let two_hundred = -56i8 as u8;
76 The semantics of numeric casts are:
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
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
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
99 [float-int]: https://github.com/rust-lang/rust/issues/10184
100 [float-float]: https://github.com/rust-lang/rust/issues/15536
104 Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.md) to and
105 from integers, and to cast between pointers to different types subject to
106 some constraints. It is only unsafe to dereference the pointer:
109 let a = 300 as *const char; // a pointer to location 300
113 `e as U` is a valid pointer cast in any of the following cases:
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*
118 * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
120 * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
122 * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
124 * `e` is a function pointer type and `U` has type `*T`,
125 while `T: Sized`; *fptr-ptr-cast*
127 * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
132 `as` only allows safe casting, and will for example reject an attempt to
133 cast four bytes into a `u32`:
136 let a = [0u8, 0u8, 0u8, 0u8];
138 let b = a as u32; // four eights makes 32
144 error: non-scalar cast: `[u8; 4]` as `u32`
145 let b = a as u32; // four eights makes 32
149 This is a ‘non-scalar cast’ because we have multiple values here: the four
150 elements of the array. These kinds of casts are very dangerous, because they
151 make assumptions about the way that multiple underlying structures are
152 implemented. For this, we need something more dangerous.
154 The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
155 what it does is very simple, but very scary. It tells Rust to treat a value of
156 one type as though it were another type. It does this regardless of the
157 typechecking system, and completely trusts you.
159 [intrinsics]: intrinsics.html
161 In our previous example, we know that an array of four `u8`s represents a `u32`
162 properly, and so we want to do the cast. Using `transmute` instead of `as`,
169 let a = [0u8, 0u8, 0u8, 0u8];
171 let b = mem::transmute::<[u8; 4], u32>(a);
175 We have to wrap the operation in an `unsafe` block for this to compile
176 successfully. Technically, only the `mem::transmute` call itself needs to be in
177 the block, but it's nice in this case to enclose everything related, so you
178 know where to look. In this case, the details about `a` are also important, and
179 so they're in the block. You'll see code in either style, sometimes the context
180 is too far away, and wrapping all of the code in `unsafe` isn't a great idea.
182 While `transmute` does very little checking, it will at least make sure that
183 the types are the same size. This errors:
189 let a = [0u8, 0u8, 0u8, 0u8];
191 let b = mem::transmute::<[u8; 4], u64>(a);
198 error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
202 Other than that, you're on your own!