9.3 Updating Struct Instances
9.3.1 Struct Update Syntax
Rust provides a convenient way to create a new struct instance by copying most of the values from another instance. This is called struct update syntax.
let new_instance = StructName {
field1: new_value1,
..old_instance
};
- The
..
syntax copies the remaining fields fromold_instance
. - Field Order: The
..old_instance
must be specified last.
Example:
struct Person { name: String, age: u8, } fn main() { let person1 = Person { name: String::from("Carol"), age: 22, }; let person2 = Person { name: String::from("Dave"), ..person1 }; println!("{} is {} years old.", person2.name, person2.age); }
- Note:
person2
will havename
set to"Dave"
andage
set to22
, copied fromperson1
.
Ownership Considerations
Using ..person1
in struct update syntax moves the values from person1
to person2
. After this operation, person1
cannot be used if it contains types that do not implement the Copy
trait (such as String
).
struct Person { name: String, age: u8, } fn main() { let person1 = Person { name: String::from("Carol"), age: 22, }; let person2 = Person { name: String::from("Dave"), ..person1 }; // println!("Person1's name: {}", person1.name); // Error: borrow of moved value }
- Since
String
does not implementCopy
,person1.name
has been moved toperson2.name
, andperson1
can no longer be used.
9.3.2 Field Init Shorthand
When the field name and the variable name are the same, you can use shorthand initialization.
let name = String::from("Eve");
let age = 28;
let person = Person { name, age };
- This is equivalent to:
let person = Person {
name: name,
age: age,
};
9.3.3 Using Default Values
If a struct implements the Default
trait, you can create a default instance and then override specific fields.
First, derive the Default
trait:
#![allow(unused)] fn main() { #[derive(Default)] struct Person { name: String, age: u8, } }
You can create a default instance in two ways:
-
Using
Person::default()
:let person = Person::default();
-
Using
Default::default()
:let person: Person = Default::default();
- Note: Both methods are equivalent;
Person::default()
explicitly calls thedefault
function for thePerson
type, whileDefault::default()
relies on type inference to determine whichdefault
function to call.
Creating an Instance with All Default Values
You can create an instance with all fields set to their default values:
let mut anna = Person::default();
- This creates a
Person
instance wherename
is an emptyString
, andage
is0
(the default value foru8
).
Using Default Values in Struct Update Syntax
You can create a new instance by overriding some fields and filling in the rest with default values:
let person = Person {
name: String::from("Eve"),
..Person::default()
};
- Here, we explicitly call
Person::default()
to provide the default values for the remaining fields.
When to Use Which
- Use
Person::default()
when you want to be explicit about the type. - Use
Default::default()
when the type can be inferred, or when you prefer the more general approach.
9.3.4 Implementing the Default
Trait Manually
If you need custom default values or cannot derive Default
, you can implement the Default
trait manually:
impl Default for Person {
fn default() -> Self {
Person {
name: String::from("Unknown"),
age: 0,
}
}
}
You can then use Person::default()
or Default::default()
as before.