]> git.lizzy.rs Git - rust.git/blob - src/doc/book/casting-between-types.md
Copy in some documentation about which casts are legal
[rust.git] / src / doc / book / casting-between-types.md
1 % Casting Between Types
2
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 safe casting:
11
12 ```rust
13 let x: i32 = 5;
14
15 let y = x as i64;
16 ```
17
18 There are three major categories of safe cast: explicit coercions, casts
19 between numeric types, and pointer casts.
20
21 Casting is not transitive: even if `e as U1 as U2` is a valid
22 expression, `e as U2` is not necessarily so (in fact it will only be valid if
23 `U1` coerces to `U2`).
24
25
26 ## Explicit coercions
27
28 A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
29
30 For example:
31
32 ```rust
33 let a = "hello";
34 let b = a as String
35 ```
36
37 Coercions always occur implicitly so this form is only for clarity.
38
39 ## Numeric casts
40
41 A cast `e as U` is also valid in any of the following cases:
42
43  * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
44  * `e` is a C-like enum and `U` is an integer type; *enum-cast*
45  * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
46  * `e` has type `u8` and `U` is `char`; *u8-char-cast*
47  
48 For example
49
50 ```rust
51 let one = true as u8;
52 let at_sign = 64 as char;
53 ```
54  
55 ## Pointer casts
56  
57 Perhaps surprisingly, it is safe to cast pointers to and from integers, and
58 to cast between pointers to different types subject to some constraints. It
59 is only unsafe to dereference the pointer.
60
61 * `e` has type `*T`, `U` is a pointer to `*U_0`, and either `U_0: Sized` or
62   unsize_kind(`T`) = unsize_kind(`U_0`); a *ptr-ptr-cast*
63 * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
64 * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
65 * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
66 * `e` is a function pointer type and `U` has type `*T`,
67   while `T: Sized`; *fptr-ptr-cast*
68 * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
69
70
71 # `transmute`
72
73 `as` only allows safe casting, and will for example reject an attempt to
74 cast four bytes into a `u32`:
75
76 ```rust,ignore
77 let a = [0u8, 0u8, 0u8, 0u8];
78
79 let b = a as u32; // four eights makes 32
80 ```
81
82 This errors with:
83
84 ```text
85 error: non-scalar cast: `[u8; 4]` as `u32`
86 let b = a as u32; // four eights makes 32
87         ^~~~~~~~
88 ```
89
90 This is a ‘non-scalar cast’ because we have multiple values here: the four
91 elements of the array. These kinds of casts are very dangerous, because they
92 make assumptions about the way that multiple underlying structures are
93 implemented. For this, we need something more dangerous.
94
95 The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
96 what it does is very simple, but very scary. It tells Rust to treat a value of
97 one type as though it were another type. It does this regardless of the
98 typechecking system, and just completely trusts you.
99
100 [intrinsics]: intrinsics.html
101
102 In our previous example, we know that an array of four `u8`s represents a `u32`
103 properly, and so we want to do the cast. Using `transmute` instead of `as`,
104 Rust lets us:
105
106 ```rust
107 use std::mem;
108
109 unsafe {
110     let a = [0u8, 0u8, 0u8, 0u8];
111
112     let b = mem::transmute::<[u8; 4], u32>(a);
113 }
114 ```
115
116 We have to wrap the operation in an `unsafe` block for this to compile
117 successfully. Technically, only the `mem::transmute` call itself needs to be in
118 the block, but it's nice in this case to enclose everything related, so you
119 know where to look. In this case, the details about `a` are also important, and
120 so they're in the block. You'll see code in either style, sometimes the context
121 is too far away, and wrapping all of the code in `unsafe` isn't a great idea.
122
123 While `transmute` does very little checking, it will at least make sure that
124 the types are the same size. This errors:
125
126 ```rust,ignore
127 use std::mem;
128
129 unsafe {
130     let a = [0u8, 0u8, 0u8, 0u8];
131
132     let b = mem::transmute::<[u8; 4], u64>(a);
133 }
134 ```
135
136 with:
137
138 ```text
139 error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
140 (64 bits)
141 ```
142
143 Other than that, you're on your own!