Builder patterns are also super helpful for libraries. Allows you to create APIs with lots of optional fields without having call sites that pass in a dozen None values.
There's also the type state pattern where you have a struct take a generic so you can allow certain methods depending on the generic type. Like say you have a struct with a field that you want to be optional, but you know statically that at a certain point in the code it'll be set.
You can do:
struct User<IdType> {
id: IdType
}
impl User<()> {
fn create() -> User<u64> {
...
}
}
impl User<u64> {
fn id() -> u64 {
user.id
}
}
That way you can have some methods where you can be certain that the ID is set and some methods where it's not set.