The entire instance must be mutable. Rust doesnโt allow us to mark only certain fields as mutable.
Keys can be omitted like in JS:
Struct update syntax:
If range operator ..
would include movable data (strings for example), we would โmoveโ user1
and could no longer use it.
In this example, we can no longer use
user1
as a whole after creatinguser2
because theString
in theusername
field ofuser1
was moved intouser2
. If we had givenuser2
newString
values for bothusername
, and thus only used theactive
andsign_in_count
values fromuser1
, thenuser1
would still be valid after creatinguser2
. Bothactive
andsign_in_count
are types that implement theCopy
trait, so the behavior we discussed in the โStack-Only Data: Copyโ section would apply.
Tuple structs
Structs that look similar to tuples. Tuple structs have the added meaning the struct name provides but donโt have names associated with their fields.
Tuple structs are useful when you want to give the whole tuple a name and make the tuple a different type from other tuples, and when naming each field as in a regular struct would be verbose or redundant.
Unit-like structs (without fields)
Unit-like structs can be useful when you need to implement a trait on some type but donโt have any data that you want to store in the type itself.
These are called unit-like structs because they behave similarly to ()
Most of the time you want to use types that will imply the ownership of a struct data (String
instead of string slice type &str
), so that data is valid for as long as the entire struct is valid.
Struct can store references to data as well owned by something else, but you would need to use lifetimes.
Methods
Methods defined within the implementation block.
&self
is short for self: &Self
.
Within an impl
block, the type Self
is an alias for the type that the impl
block is for.
Methods can take ownership of self
(self
), borrow self
immutably (&self
) or borrow self
mutably (&mut self
), just as they can any other parameter.
we can choose to give a method the same name as one of the structโs fields. When calling with parentheses, Rust will call a method, when using w/o parentheses, Rust will return a fieldโs value.
Rust has automatic referencing and dereferencing. when you call a method with object.something()
, Rust automatically adds in &
, &mut
, or *
so object
matches the signature of the method. In other words, the following are the same:
This automatic referencing behavior works because methods have a clear receiverโthe type of self
. Given the receiver and name of a method, Rust can figure out definitively whether the method is reading (&self
), mutating (&mut self
), or consuming (self
). The fact that Rust makes borrowing implicit for method receivers is a big part of making ownership ergonomic in practice.
All functions defined within an impl
block are called associated functions because theyโre associated with the type named after the impl
.
e 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, e.g. String::new
or String::from
.
Each struct is allowed to have multiple impl
blocks.