Which of these code styles do you find preferable?
First option using mut with constructor in the beginning:
let mut post_form = PostInsertForm::new(
data.name.trim().to_string(),
local_user_view.person.id,
data.community_id,
);
post_form.url = url.map(Into::into);
post_form.body = body;
post_form.alt_text = data.alt_text.clone();
post_form.nsfw = data.nsfw;
post_form.language_id = language_id;
Second option without mut and constructor at the end:
let post_form = PostInsertForm {
url: url.map(Into::into),
body,
alt_text: data.alt_text.clone(),
nsfw: data.nsfw,
language_id,
..PostInsertForm::new(
data.name.trim().to_string(),
local_user_view.person.id,
data.community_id,
)
};
You can see the full PR here: https://github.com/LemmyNet/lemmy/pull/5037/files
If you’re ever forced to do something the second way, you can also wrap it in braces, that way you end up with an immutable value again:
let app = { let mut app = ... ... app };
Thats even more verbose so the second option is better.
Yeah if you have the second option, use it, but if the struct has private fields it won’t work.
The first one won’t work either for private fields.
You can have setters that set private fields, there are also sometimes structs with mixed private and public fields
But why not use a proper builder pattern in that case?
Because you don’t control third party libraries
Why not just a
let app = app;
line after thelet mut app = ...;
one?A scope groups the initialization visually together, while adding the
let app = app;
feels like it just adds clutter - I’d probably just leave it mut in that case.Rebinding with and without
mut
is a known and encouraged pattern in rust. Leaving things asmut
longer than necessary is not.But a scope adds a nesting level which adds a lot more visual clutter.