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?
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;
}
}
}
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;
}
}
}
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).
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With