Calling a method on a value inside a mutable Option
As a follow-up to @idupree's variant, it is also possible to use if-let syntax:
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x = 0;
}
}
}
I'd also argue that this is more idiomatic than map()
, because map()
method is intended for transforming an Option
, not executing side effects (and assignment is a side effect).
As Vladimir Matveev points out, if let
is even nicer, and is more idiomatic than iterating over the Option
:
#[derive(Debug)]
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x += 1;
}
}
}
fn main() {
let mut f = Foo { stream: Some(0) };
println!("{:?}", f);
f.send();
println!("{:?}", f);
}
As of Rust 1.26, match ergonomics allows you to omit some of the keywords:
impl Foo {
fn send(&mut self) {
if let Some(x) = &mut self.stream {
*x += 1;
}
}
}
Before that, I would usually use Option::as_mut
:
impl Foo {
fn send(&mut self) {
if let Some(x) = self.stream.as_mut() {
*x += 1;
}
}
}
Other options
As Vladimir Matveev points out (again!), map
is usually used to transform data, not for side effects (which I agree with). You could instead use iter_mut
(or the shorthand of &mut collection
), as I feel that iteration is usually for side effects. I like this because it means our code can avoid having a conditional:
impl Foo {
fn send(&mut self) {
for x in &mut self.stream {
*x += 1;
}
}
}
You can also leverage the IntoIterator
implementation for Option
:
impl Foo {
fn send(&mut self) {
for x in self.stream.as_mut() {
*x += 1;
}
}
}
You can match on the Option
directly, like the following (showing i32
rather than TcpStream
):
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
match self.stream {
Some(ref mut x) => {
*x = 0;
}
None => {}
}
}
}
(Not sure whether that's the most idiomatic way to do it.)