Struct Update Syntax / Nesting
Rust structs support two powerful features: the struct update syntax, which creates a new instance by copying fields from an existing one, and nested structs, which let you model complex data by embedding one struct inside another.
Syntax
// Struct update syntax: copies remaining fields from an existing instance.
struct Config {
debug: bool,
timeout: u32,
max_connections: u32,
}
let default_cfg = Config { debug: false, timeout: 30, max_connections: 100 };
// Creates a new Config with only debug changed.
let dev_cfg = Config {
debug: true,
..default_cfg // Copies the remaining fields from default_cfg.
};
// Example of nested structs.
struct Address {
city: String,
country: String,
}
struct Person {
name: String,
age: u32,
address: Address, // Nests a struct inside another struct.
}
Concept overview
| Syntax / Concept | Description |
|---|---|
| Struct { field: val, ..other } | Creates a new instance with some fields specified explicitly; the remaining fields are copied from other. |
| Nested structs | A struct field can itself be another struct. |
| s.inner.field | Access nested fields by chaining dot notation. |
| Default::default() | Generates an instance with default values when #[derive(Default)] is present. Can be combined with the update syntax. |
| Struct destructuring | Use let Struct { field1, field2, .. } = s; to extract fields into variables. |
| Pattern matching with match | Use match s { Struct { field1: x, .. } => ... } to match on specific fields only. |
Sample code
#[derive(Debug, Clone, Default)]
struct ServerConfig {
host: String,
port: u16,
max_connections: u32,
timeout_secs: u64,
debug_mode: bool,
}
#[derive(Debug)]
struct Rgb {
r: u8,
g: u8,
b: u8,
}
#[derive(Debug)]
struct Theme {
name: String,
primary: Rgb,
secondary: Rgb,
background: Rgb,
}
fn main() {
// Derives a new config from an existing one using the struct update syntax.
let prod = ServerConfig {
host: String::from("prod.example.com"),
port: 443,
max_connections: 1000,
timeout_secs: 30,
debug_mode: false,
};
// Creates a development config with only the host, port, and debug_mode changed.
let dev = ServerConfig {
host: String::from("localhost"),
port: 8080,
debug_mode: true,
..prod.clone() // Copies the remaining fields from prod.
};
println!("dev: {:?}", dev);
// Combines Default with the struct update syntax.
let minimal = ServerConfig {
host: String::from("localhost"),
port: 3000,
..Default::default() // Remaining fields use their defaults (numbers → 0, bool → false).
};
println!("minimal: {:?}", minimal);
// Accessing fields of a nested struct.
let theme = Theme {
name: String::from("Ocean"),
primary: Rgb { r: 0, g: 120, b: 200 },
secondary: Rgb { r: 0, g: 80, b: 150 },
background: Rgb { r: 240, g: 248, b: 255 },
};
println!("Theme name: {}", theme.name);
println!("Primary color R: {}", theme.primary.r);
println!("Background RGB: ({}, {}, {})",
theme.background.r, theme.background.g, theme.background.b);
// Destructuring a struct.
let Rgb { r, g, b } = theme.primary;
println!("Destructured: r={}, g={}, b={}", r, g, b);
// Pattern matching with match (matching on specific fields only).
let config = ServerConfig {
host: String::from("api.example.com"),
port: 443,
..Default::default()
};
match config {
ServerConfig { port: 443, debug_mode: false, .. } => {
println!("Production HTTPS server");
}
ServerConfig { debug_mode: true, .. } => {
println!("Debug mode enabled");
}
_ => println!("Other configuration"),
}
}
Notes
When using the struct update syntax (..other), fields of a Copy type are copied without issue. However, heap-allocated types such as String are moved, transferring ownership. If you need to keep the original value intact, call clone() beforehand.
Combining Default::default() with the update syntax is a common pattern for configuration structs — it works well when most fields have sensible defaults and you only need to customize a few.
For automatically derived trait implementations, see #[derive(Debug, Clone, PartialEq)].
If you find any errors or copyright issues, please contact us.