Skip to content

Commit 0117de1

Browse files
committed
Add union items to the reference
1 parent e793ca8 commit 0117de1

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

src/items.md

+137
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ There are several kinds of item:
2121
* [type definitions](../grammar.html#type-definitions)
2222
* [struct definitions](#structs)
2323
* [enumeration definitions](#enumerations)
24+
* [union definitions](#unions)
2425
* [constant items](#constant-items)
2526
* [static items](#static-items)
2627
* [trait definitions](#traits)
@@ -569,6 +570,142 @@ let x = Foo::Bar as u32; // x is now 123u32
569570
This only works as long as none of the variants have data attached. If
570571
it were `Bar(i32)`, this is disallowed.
571572

573+
## Unions
574+
575+
A union declaration uses the same syntax as a struct declaration, except with
576+
`union` in place of `struct`.
577+
578+
```rust
579+
#[repr(C)]
580+
union MyUnion {
581+
f1: u32,
582+
f2: f32,
583+
}
584+
```
585+
586+
The key property of unions is that all fields of a union share common storage.
587+
As a result writes to one field of a union can overwrite its other fields,
588+
and size of a union is determined by the size of its largest field.
589+
590+
A value of a union type can be created using the same syntax that is used for
591+
struct types, except that it must specify exactly one field:
592+
593+
```rust
594+
let u = MyUnion { f1: 1 };
595+
```
596+
597+
The expression above creates a value of type `MyUnion` with active field `f1`.
598+
Active field of a union can be accessed using the same syntax as struct fields:
599+
600+
```rust
601+
let f = u.f1;
602+
```
603+
604+
Inactive fields can be accessed as well (using the same syntax) if they are
605+
sufficiently layout compatible with the
606+
current value kept by the union. Reading incompatible fields results in
607+
undefined behavior.
608+
However, the active field is not generally known statically, so all reads of
609+
union fields have to be placed in `unsafe` blocks.
610+
611+
```rust
612+
unsafe {
613+
let f = u.f1;
614+
}
615+
```
616+
617+
Writes to union fields may generally require reads (for running destructors),
618+
so these writes have to be placed in `unsafe` blocks too.
619+
620+
```rust
621+
unsafe {
622+
u.f1 = 2;
623+
}
624+
```
625+
626+
Commonly, code using unions will provide safe wrappers around unsafe
627+
union field accesses.
628+
629+
Another way to access union fields is to use pattern matching.
630+
Pattern matching on union fields uses the same syntax as struct patterns,
631+
except that the pattern must specify exactly one field.
632+
Since pattern matching accesses potentially inactive fields it has
633+
to be placed in `unsafe` blocks as well.
634+
635+
```rust
636+
fn f(u: MyUnion) {
637+
unsafe {
638+
match u {
639+
MyUnion { f1: 10 } => { println!("ten"); }
640+
MyUnion { f2 } => { println!("{}", f2); }
641+
}
642+
}
643+
}
644+
```
645+
646+
Pattern matching may match a union as a field of a larger structure. In
647+
particular, when using a Rust union to implement a C tagged union via FFI, this
648+
allows matching on the tag and the corresponding field simultaneously:
649+
650+
```rust
651+
#[repr(u32)]
652+
enum Tag { I, F }
653+
654+
#[repr(C)]
655+
union U {
656+
i: i32,
657+
f: f32,
658+
}
659+
660+
#[repr(C)]
661+
struct Value {
662+
tag: Tag,
663+
u: U,
664+
}
665+
666+
fn is_zero(v: Value) -> bool {
667+
unsafe {
668+
match v {
669+
Value { tag: I, u: U { i: 0 } } => true,
670+
Value { tag: F, u: U { f: 0.0 } } => true,
671+
_ => false,
672+
}
673+
}
674+
}
675+
```
676+
677+
Since union fields share common storage, gaining write access to one
678+
field of a union can give write access to all its remaining fields.
679+
Borrow checking rules have to be adjusted to account for this fact.
680+
As a result, if one field of a union is borrowed, all its remaining fields
681+
are borrowed as well for the same lifetime.
682+
683+
```rust
684+
// ERROR: cannot borrow `u` (via `u.f2`) as mutable more than once at a time
685+
fn test() {
686+
let mut u = MyUnion { f1: 1 };
687+
unsafe {
688+
let b1 = &mut u.f1;
689+
---- first mutable borrow occurs here (via `u.f1`)
690+
let b2 = &mut u.f2;
691+
^^^^ second mutable borrow occurs here (via `u.f2`)
692+
*b1 = 5;
693+
}
694+
- first borrow ends here
695+
assert_eq!(unsafe { u.f1 }, 5);
696+
}
697+
```
698+
699+
As you could see, in many aspects (except for layouts, safety and ownership)
700+
unions behave exactly like structs, largely as a consequence of inheriting their
701+
syntactic shape from structs.
702+
This is also true for many unmentioned aspects of Rust language (such as
703+
privacy, name resolution, type inference, generics, trait implementations,
704+
inherent implementations, coherence, pattern checking, etc etc etc).
705+
706+
More detailed specification for unions, including unstable bits, can be found in
707+
[RFC 1897 "Unions v1.2"](https://github.com/rust-lang/rfcs/pull/1897).
708+
572709
## Constant items
573710

574711
A *constant item* is a named _constant value_ which is not associated with a

0 commit comments

Comments
 (0)