Struct
Defining and Instantiating Structs
Note that the entire instance must be mutable; Rust doesn’t allow us to mark only certain fields as mutable. As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance.
The email
and sign_in_count
is of type String
. We want each instance of the struct owns all of its data. If we use a &str
, the variables are not owned by the struct instance.
It uses field init shorthand syntax.
This is struct update syntax. The ..user1
must come last to specify that any remaining fields should get their values from the corresponding fields in user1
, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition.
Note that this is a move. We can no longer use user1
as a whole as a whole after creating user2
.
In this example, we can no longer use user1
as a whole after creating user2
because the String
in the username
field of user1
was moved into user2
. If we had given user2
new String
values for both email
and username
, and thus only used the active
and sign_in_count
values from user1
, then user1
would still be valid after creating user2
. Both active
and sign_in_count
are types that implement the Copy
trait, so the behavior we discussed in the “Stack-Only Data: Copy” section would apply.
Tuple Structs
An Example Program Using Structs
To print out the structure we can use an output format called Debug
.
We can use {:#?}
instead of {:?}
in the println!
string for larger structs.
Another way to print out a value using the Debug
format is to use the dbg!
macro, which takes the ownership of an expression (as opposed to println!
, which takes a reference), prints the file and line number of where that dbg!
macro call ocuurs in your code along with the resultant value of that expression, and returns ownership of the value.
Method Syntax
To define the function within the context of Rectangle
, we start an impl
block for Rectangle
The &self
is actually short for self: &Self
. Within an impl
block, the type Self
is an alias for the type that the impl
block is for.
If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self
as the first parameter.
Methods with the same name as a field usually return the value in the field and do nothing else. Methods like this are called getters, and Rust does not implement them automatically for struct fields as some other languages do.
Methods with More Parameters
Associated Functions
We can define associated functions that don’t have self
as their first parameter (and thus are not methods) because they don’t need an instance of the type to work with.
The Self
keywords in the return type and in the body of the function are aliases for the type that appears after the impl
keyword, which in this case is Rectangle
.
To call this associated function, we use the ::
syntax with the struct name; let sq = Rectangle::square(3);
is an example. This function is namespaced by the struct: the ::
syntax is used for both associated functions and namespaces created by modules.
Last updated