Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Calling a method on a value inside a mutable Option

I have a mutable Option type and I'm trying to mutate the thing inside the Some but I can't figure out how to do it.

use std::net::TcpStream;
use std::io::Write;

struct Foo {
    stream: Option<TcpStream>,
}

impl Foo {
    fn send(&mut self) {
        self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
    }
}

This produces the error:

error[E0596]: cannot borrow immutable argument `x` as mutable
  --> src/main.rs:10:29
   |
10 |         self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
   |                          -  ^ cannot borrow mutably
   |                          |
   |                          consider changing this to `mut x`

Can someone try to implement send as an example to help me understand?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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;
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...