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.)

Tags:

Rust