]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | # Unions |
2 | ||
8faf50e0 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _Union_ :\ | |
5869c6ff | 5 | > `union` [IDENTIFIER] [_GenericParams_]<sup>?</sup> [_WhereClause_]<sup>?</sup> |
ff7c6d11 XL |
6 | > `{`[_StructFields_] `}` |
7 | ||
ea8adc8c XL |
8 | A union declaration uses the same syntax as a struct declaration, except with |
9 | `union` in place of `struct`. | |
10 | ||
11 | ```rust | |
12 | #[repr(C)] | |
13 | union MyUnion { | |
14 | f1: u32, | |
15 | f2: f32, | |
16 | } | |
17 | ``` | |
18 | ||
19 | The key property of unions is that all fields of a union share common storage. | |
ba9703b0 | 20 | As a result, writes to one field of a union can overwrite its other fields, and |
ea8adc8c XL |
21 | size of a union is determined by the size of its largest field. |
22 | ||
416331ca XL |
23 | ## Initialization of a union |
24 | ||
ea8adc8c XL |
25 | A value of a union type can be created using the same syntax that is used for |
26 | struct types, except that it must specify exactly one field: | |
27 | ||
28 | ```rust | |
29 | # union MyUnion { f1: u32, f2: f32 } | |
30 | # | |
31 | let u = MyUnion { f1: 1 }; | |
32 | ``` | |
33 | ||
532ac7d7 XL |
34 | The expression above creates a value of type `MyUnion` and initializes the |
35 | storage using field `f1`. The union can be accessed using the same syntax as | |
36 | struct fields: | |
ea8adc8c | 37 | |
60c5eb7d XL |
38 | ```rust |
39 | # union MyUnion { f1: u32, f2: f32 } | |
40 | # | |
41 | # let u = MyUnion { f1: 1 }; | |
42 | let f = unsafe { u.f1 }; | |
ea8adc8c XL |
43 | ``` |
44 | ||
416331ca XL |
45 | ## Reading and writing union fields |
46 | ||
532ac7d7 XL |
47 | Unions have no notion of an "active field". Instead, every union access just |
48 | interprets the storage at the type of the field used for the access. Reading a | |
416331ca | 49 | union field reads the bits of the union at the field's type. Fields might have a |
6a06907d XL |
50 | non-zero offset (except when [the C representation] is used); in that case the |
51 | bits starting at the offset of the fields are read. It is the programmer's | |
416331ca | 52 | responsibility to make sure that the data is valid at the field's type. Failing |
6a06907d XL |
53 | to do so results in [undefined behavior]. For example, reading the value `3` |
54 | through of a field of the [boolean type] is undefined behavior. Effectively, | |
55 | writing to and then reading from a union with [the C representation] is | |
56 | analogous to a [`transmute`] from the type used for writing to the type used for | |
57 | reading. | |
532ac7d7 XL |
58 | |
59 | Consequently, all reads of union fields have to be placed in `unsafe` blocks: | |
ea8adc8c XL |
60 | |
61 | ```rust | |
62 | # union MyUnion { f1: u32, f2: f32 } | |
63 | # let u = MyUnion { f1: 1 }; | |
64 | # | |
65 | unsafe { | |
66 | let f = u.f1; | |
67 | } | |
68 | ``` | |
69 | ||
fc512014 XL |
70 | Writes to [`Copy`] or [`ManuallyDrop`][ManuallyDrop] union fields do not |
71 | require reads for running destructors, so these writes don't have to be placed | |
72 | in `unsafe` blocks | |
ea8adc8c XL |
73 | |
74 | ```rust | |
fc512014 XL |
75 | # use std::mem::ManuallyDrop; |
76 | union MyUnion { f1: u32, f2: ManuallyDrop<String> } | |
77 | let mut u = MyUnion { f1: 1 }; | |
78 | ||
79 | // These do not require `unsafe`. | |
ea8adc8c | 80 | u.f1 = 2; |
fc512014 | 81 | u.f2 = ManuallyDrop::new(String::from("example")); |
ea8adc8c XL |
82 | ``` |
83 | ||
84 | Commonly, code using unions will provide safe wrappers around unsafe union | |
85 | field accesses. | |
86 | ||
29967ef6 XL |
87 | ## Unions and `Drop` |
88 | ||
89 | When a union is dropped, it cannot know which of its fields needs to be dropped. | |
fc512014 XL |
90 | For this reason, all union fields must either be of a [`Copy`] type or of the |
91 | shape [`ManuallyDrop<_>`][ManuallyDrop]. This ensures that a union does not | |
92 | need to drop anything when it goes out of scope. | |
29967ef6 XL |
93 | |
94 | Like for structs and enums, it is possible to `impl Drop` for a union to | |
95 | manually define what happens when it gets dropped. | |
96 | ||
416331ca XL |
97 | ## Pattern matching on unions |
98 | ||
ea8adc8c | 99 | Another way to access union fields is to use pattern matching. Pattern matching |
532ac7d7 XL |
100 | on union fields uses the same syntax as struct patterns, except that the pattern |
101 | must specify exactly one field. Since pattern matching is like reading the union | |
102 | with a particular field, it has to be placed in `unsafe` blocks as well. | |
ea8adc8c XL |
103 | |
104 | ```rust | |
105 | # union MyUnion { f1: u32, f2: f32 } | |
106 | # | |
107 | fn f(u: MyUnion) { | |
108 | unsafe { | |
109 | match u { | |
110 | MyUnion { f1: 10 } => { println!("ten"); } | |
111 | MyUnion { f2 } => { println!("{}", f2); } | |
112 | } | |
113 | } | |
114 | } | |
115 | ``` | |
116 | ||
117 | Pattern matching may match a union as a field of a larger structure. In | |
118 | particular, when using a Rust union to implement a C tagged union via FFI, this | |
119 | allows matching on the tag and the corresponding field simultaneously: | |
120 | ||
121 | ```rust | |
122 | #[repr(u32)] | |
123 | enum Tag { I, F } | |
124 | ||
125 | #[repr(C)] | |
126 | union U { | |
127 | i: i32, | |
128 | f: f32, | |
129 | } | |
130 | ||
131 | #[repr(C)] | |
132 | struct Value { | |
133 | tag: Tag, | |
134 | u: U, | |
135 | } | |
136 | ||
137 | fn is_zero(v: Value) -> bool { | |
138 | unsafe { | |
139 | match v { | |
e74abb32 XL |
140 | Value { tag: Tag::I, u: U { i: 0 } } => true, |
141 | Value { tag: Tag::F, u: U { f: num } } if num == 0.0 => true, | |
ea8adc8c XL |
142 | _ => false, |
143 | } | |
144 | } | |
145 | } | |
146 | ``` | |
147 | ||
416331ca XL |
148 | ## References to union fields |
149 | ||
ea8adc8c XL |
150 | Since union fields share common storage, gaining write access to one field of a |
151 | union can give write access to all its remaining fields. Borrow checking rules | |
152 | have to be adjusted to account for this fact. As a result, if one field of a | |
153 | union is borrowed, all its remaining fields are borrowed as well for the same | |
154 | lifetime. | |
155 | ||
60c5eb7d XL |
156 | ```rust,compile_fail |
157 | # union MyUnion { f1: u32, f2: f32 } | |
ea8adc8c XL |
158 | // ERROR: cannot borrow `u` (via `u.f2`) as mutable more than once at a time |
159 | fn test() { | |
160 | let mut u = MyUnion { f1: 1 }; | |
161 | unsafe { | |
162 | let b1 = &mut u.f1; | |
60c5eb7d | 163 | // ---- first mutable borrow occurs here (via `u.f1`) |
ea8adc8c | 164 | let b2 = &mut u.f2; |
60c5eb7d | 165 | // ^^^^ second mutable borrow occurs here (via `u.f2`) |
ea8adc8c XL |
166 | *b1 = 5; |
167 | } | |
60c5eb7d | 168 | // - first borrow ends here |
ea8adc8c XL |
169 | assert_eq!(unsafe { u.f1 }, 5); |
170 | } | |
171 | ``` | |
172 | ||
e1599b0c | 173 | As you could see, in many aspects (except for layouts, safety, and ownership) |
ea8adc8c XL |
174 | unions behave exactly like structs, largely as a consequence of inheriting |
175 | their syntactic shape from structs. This is also true for many unmentioned | |
176 | aspects of Rust language (such as privacy, name resolution, type inference, | |
177 | generics, trait implementations, inherent implementations, coherence, pattern | |
178 | checking, etc etc etc). | |
179 | ||
416331ca | 180 | [IDENTIFIER]: ../identifiers.md |
5869c6ff | 181 | [_GenericParams_]: generics.md |
416331ca XL |
182 | [_WhereClause_]: generics.md#where-clauses |
183 | [_StructFields_]: structs.md | |
184 | [`transmute`]: ../../std/mem/fn.transmute.html | |
fc512014 | 185 | [`Copy`]: ../../std/marker/trait.Copy.html |
6a06907d | 186 | [boolean type]: ../types/boolean.md |
fc512014 | 187 | [ManuallyDrop]: ../../std/mem/struct.ManuallyDrop.html |
6a06907d XL |
188 | [the C representation]: ../type-layout.md#reprc-unions |
189 | [undefined behavior]: ../behavior-considered-undefined.html |