Struct expressions
Syntax
StructExpression →
PathInExpression { ( StructExprFields | StructBase )? }
StructExprFields →
StructExprField ( , StructExprField )* ( , StructBase | ,? )
StructExprField →
OuterAttribute*
(
IDENTIFIER
| ( IDENTIFIER | TUPLE_INDEX ) : Expression
)
StructBase → .. Expression
A struct expression creates a struct, enum, or union value. It consists of a path to a struct, enum variant, or union item followed by the values for the fields of the item.
The following are examples of struct expressions:
#![allow(unused)] fn main() { struct Point { x: f64, y: f64 } struct NothingInMe { } mod game { pub struct User<'a> { pub name: &'a str, pub age: u32, pub score: usize } } enum Enum { Variant {} } Point {x: 10.0, y: 20.0}; NothingInMe {}; let u = game::User {name: "Joe", age: 35, score: 100_000}; Enum::Variant {}; }
Note
Tuple structs and tuple enum variants are typically instantiated using a call expression referring to the constructor in the value namespace. These are distinct from a struct expression using curly braces referring to the constructor in the type namespace.
#![allow(unused)] fn main() { struct Position(i32, i32, i32); Position(0, 0, 0); // Typical way of creating a tuple struct. let c = Position; // `c` is a function that takes 3 arguments. let pos = c(8, 6, 7); // Creates a `Position` value. enum Version { Triple(i32, i32, i32) }; Version::Triple(0, 0, 0); let f = Version::Triple; let ver = f(8, 6, 7); }
The last segment of the call path cannot refer to a type alias:
#![allow(unused)] fn main() { trait Tr { type T; } impl<T> Tr for T { type T = T; } struct Tuple(); enum Enum { Tuple() } // <Unit as Tr>::T(); // causes an error -- `::T` is a type, not a value <Enum as Tr>::T::Tuple(); // OK }
Unit structs and unit enum variants are typically instantiated using a path expression referring to the constant in the value namespace.
#![allow(unused)] fn main() { struct Gamma; // Gamma unit value, referring to the const in the value namespace. let a = Gamma; // Exact same value as `a`, but constructed using a struct expression // referring to the type namespace. let b = Gamma {}; enum ColorSpace { Oklch } let c = ColorSpace::Oklch; let d = ColorSpace::Oklch {}; }
Field struct expression
A struct expression with fields enclosed in curly braces allows you to specify the value for each individual field in any order. The field name is separated from its value with a colon.
A value of a union type can only be created using this syntax, and it must specify exactly one field.
Functional update syntax
A struct expression that constructs a value of a struct type can terminate with the syntax ..
followed by an expression to denote a functional update.
The expression following ..
(the base) must have the same struct type as the new struct type being formed.
The entire expression uses the given values for the fields that were specified and moves or copies the remaining fields from the base expression.
As with all struct expressions, all of the fields of the struct must be visible, even those not explicitly named.
#![allow(unused)] fn main() { struct Point3d { x: i32, y: i32, z: i32 } let mut base = Point3d {x: 1, y: 2, z: 3}; let y_ref = &mut base.y; Point3d {y: 0, z: 10, .. base}; // OK, only base.x is accessed drop(y_ref); }
Struct expressions can’t be used directly in a loop or if expression’s head, or in the scrutinee of an if let or match expression. However, struct expressions can be used in these situations if they are within another expression, for example inside parentheses.
The field names can be decimal integer values to specify indices for constructing tuple structs. This can be used with base structs to fill out the remaining indices not specified:
#![allow(unused)] fn main() { struct Color(u8, u8, u8); let c1 = Color(0, 0, 0); // Typical way of creating a tuple struct. let c2 = Color{0: 255, 1: 127, 2: 0}; // Specifying fields by index. let c3 = Color{1: 0, ..c2}; // Fill out all other fields using a base struct. }
Struct field init shorthand
When initializing a data structure (struct, enum, union) with named (but not numbered) fields, it is allowed to write fieldname
as a shorthand for fieldname: fieldname
.
This allows a compact syntax with less duplication.
For example:
#![allow(unused)] fn main() { struct Point3d { x: i32, y: i32, z: i32 } let x = 0; let y_value = 0; let z = 0; Point3d { x: x, y: y_value, z: z }; Point3d { x, y: y_value, z }; }