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