Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion src/expressions/struct-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ StructExprField ->
| (IDENTIFIER | TUPLE_INDEX) `:` Expression
)

StructBase -> `..` Expression
StructBase -> `..` Expression?
```

r[expr.struct.intro]
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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<String>,
age: i128 = 42,
}

let pet = Pet { name: None, .. };
assert_eq!(valid.age, 42);
```

r[expr.struct.field.named]
### Struct field init shorthand

Expand All @@ -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
52 changes: 52 additions & 0 deletions src/items/structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ TupleStruct ->
StructFields -> StructField (`,` StructField)* `,`?

StructField -> OuterAttribute* Visibility? IDENTIFIER `:` Type
StructFieldDefault?

StructFieldDefault -> `=` Expression

TupleFields -> TupleField (`,` TupleField)* `,`?

Expand Down Expand Up @@ -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<String>,
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<String>,
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<String>, // 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
Loading