From 453d6d2947e63d91aad1a59ad7187524081b6ca0 Mon Sep 17 00:00:00 2001 From: +merlan #flirora Date: Mon, 24 Mar 2025 11:45:26 -0400 Subject: [PATCH] Add docs for field default values --- src/expressions/struct-expr.md | 78 +++++++++++++++++++++++----------- src/items/structs.md | 52 +++++++++++++++++++++++ 2 files changed, 106 insertions(+), 24 deletions(-) diff --git a/src/expressions/struct-expr.md b/src/expressions/struct-expr.md index 3c3dd15d4..33dd645d1 100644 --- a/src/expressions/struct-expr.md +++ b/src/expressions/struct-expr.md @@ -1,7 +1,9 @@ r[expr.struct] + # Struct expressions r[expr.struct.syntax] + ```grammar,expressions StructExpression -> PathInExpression `{` (StructExprFields | StructBase)? `}` @@ -16,7 +18,7 @@ StructExprField -> | (IDENTIFIER | TUPLE_INDEX) `:` Expression ) -StructBase -> `..` Expression +StructBase -> `..` Expression? ``` r[expr.struct.intro] @@ -82,6 +84,7 @@ Enum::Variant {}; > ``` r[expr.struct.field] + ## Field struct expression r[expr.struct.field.intro] @@ -91,29 +94,6 @@ The field name is separated from its value with a colon. 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.update] -## Functional update syntax - -r[expr.struct.update.intro] -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. - -r[expr.struct.update.base-same-type] -The expression following `..` (the base) must have the same struct type as the new struct type being formed. - -r[expr.struct.update.fields] -The entire expression uses the given values for the fields that were specified and moves or copies the remaining fields from the base expression. - -r[expr.struct.update.visibility-constraint] -As with all struct expressions, all of the fields of the struct must be [visible], even those not explicitly named. - -```rust -# 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); -``` - 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]. @@ -130,6 +110,7 @@ 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`. @@ -145,6 +126,54 @@ Point3d { x: x, y: y_value, z: z }; Point3d { x, y: y_value, z }; ``` +r[expr.struct.update] + +## Functional update syntax + +r[expr.struct.update.intro] +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. + +r[expr.struct.update.base-same-type] +The expression following `..` (the base) must have the same struct type as the new struct type being formed. + +r[expr.struct.update.fields] +The entire expression uses the given values for the fields that were specified and moves or copies the remaining fields from the base expression. + +r[expr.struct.update.visibility-constraint] +As with all struct expressions, all of the fields of the struct must be [visible], even those not explicitly named. + +```rust +# 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); +``` + +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); +``` + [enum variant]: ../items/enumerations.md [if let]: if-expr.md#if-let-expressions [if]: if-expr.md#if-expressions @@ -155,3 +184,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 77809007d..ff7391d22 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)* `,`? @@ -70,9 +73,58 @@ 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