Skip to content

Commit e3479cb

Browse files
authored
Merge pull request rust-lang#57 from petrochenkov/union
Add union items to the reference
2 parents d924309 + 81db079 commit e3479cb

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

src/items.md

+145
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ There are several kinds of item:
2121
* [type definitions](#type-aliases)
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)
@@ -568,6 +569,150 @@ let x = Foo::Bar as u32; // x is now 123u32
568569
This only works as long as none of the variants have data attached. If
569570
it were `Bar(i32)`, this is disallowed.
570571

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

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

0 commit comments

Comments
 (0)