diff --git a/src/expressions/struct-expr.md b/src/expressions/struct-expr.md index 0046a7dbd5..28c9d845a0 100644 --- a/src/expressions/struct-expr.md +++ b/src/expressions/struct-expr.md @@ -16,7 +16,7 @@ StructExprField -> | (IDENTIFIER | TUPLE_INDEX) `:` Expression ) -StructBase -> `..` Expression +StructBase -> `..` Expression? ``` r[expr.struct.intro] @@ -89,6 +89,37 @@ A struct expression with fields enclosed in curly braces allows you to specify t r[expr.struct.field.union-constraint] A value of a [union] type can only be created using this syntax, and it must specify exactly one field. +r[expr.struct.brace-restricted-positions] +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]. + +r[expr.struct.tuple-field] +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: + +```rust +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. +``` + +r[expr.struct.field.named] +### 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: + +```rust +# 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 }; +``` + r[expr.struct.update] ## Functional update syntax @@ -125,6 +156,29 @@ 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. ``` +r[expr.struct.default] +## Default field syntax + +r[expr.struct.default.intro] +A struct expression that constructs a value of a struct type can terminate with the syntax `..` without a following expression to denote that unlisted fields should be set to their [default values]. + +r[expr.struct.default.fields] +All fields without defualt values must be listed in the expression. +The entire expression uses the given values for the fields that were specified and initializes the remaining fields with their respective default values. + +r[expr.struct.default.visibility-constraint] +As with all struct expressions, all of the fields of the struct must be [visible], even those not explicitly named. + +```rust +struct Pet { + name: Option, + age: i128 = 42, +} + +let pet = Pet { name: None, .. }; +assert_eq!(valid.age, 42); +``` + r[expr.struct.field.named] ### Struct field init shorthand @@ -149,3 +203,4 @@ Point3d { x, y: y_value, z }; [union]: ../items/unions.md [visible]: ../visibility-and-privacy.md [scrutinee]: ../glossary.md#scrutinee +[default values]: ../items/structs.md#default-field-values diff --git a/src/items/structs.md b/src/items/structs.md index 6374a0ffd7..eddb855915 100644 --- a/src/items/structs.md +++ b/src/items/structs.md @@ -16,6 +16,9 @@ TupleStruct -> StructFields -> StructField (`,` StructField)* `,`? StructField -> OuterAttribute* Visibility? IDENTIFIER `:` Type + StructFieldDefault? + +StructFieldDefault -> `=` Expression TupleFields -> TupleField (`,` TupleField)* `,`? @@ -64,9 +67,58 @@ let c = [Cookie, Cookie {}, Cookie, Cookie {}]; r[items.struct.layout] The precise memory layout of a struct is not specified. One can specify a particular layout using the [`repr` attribute]. +r[items.struct.default] +## Default field values + +r[items.struct.default.intro] +A field in a non-tuple struct can be assigned a default value, which can be used in a [struct expression] using the [default field syntax]: + +```rust +struct Pet { + name: Option, + age: i128 = 42, +} + +let pet = Pet { name: None, .. }; +assert_eq!(valid.age, 42); +``` + +r[items.struct.default.const] +A default field value must be a [constant expression]: + +```rust,compile_fail +struct Pet { + name: Option, + age: i128 = { println!("calculating age"); 42 }, + // ERROR: cannot call non-const function `_print` in constants +} +``` + +r[item.struct.default.derive] +The [derive macro] for the [`Default`] trait will use default field values in the implementation: + +```rust +#[derive(Default)] +struct Pet { + name: Option, // impl Default for Pet will use Default::default() for name + age: i128 = 42, // impl Default for Pet will use the literal 42 for age +} + +let default = Pet::default(); +assert_eq!(default.name, None); +assert_eq!(default.age, 42); +``` + +Any fields without a default field value must have an implementation of [`Default`], +whose `default` method will be used for these fields instead. + [`repr` attribute]: ../type-layout.md#representations [constant]: constant-items.md [struct type]: ../types/struct.md +[struct expression]: ../expressions/struct-expr.md [tuple type]: ../types/tuple.md [type namespace]: ../names/namespaces.md [value namespace]: ../names/namespaces.md +[constant expression]: ../const_eval.md +[derive macro]: ../procedural-macros.md#derive-macros +[default field syntax]: ../expressions/struct-expr.md#default-field-syntax