How to change the variable from inside Fn closure in Rust? - rust

I have the following code (playground):
struct A {
pub vec: Vec<u64>,
}
impl A {
fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
for mut i in &mut self.vec {
f(i);
}
}
}
fn main() {
let mut a = A {
vec: vec![1, 3, 44, 2, 4, 5, 6],
};
let mut done = false;
a.perform_for_all(|v| {
println!("value: {:?}", v);
done = true;
});
if !done {
a.perform_for_all(|v| {
println!("value {:?}", v);
});
}
}
The following errors occur:
error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
--> src/main.rs:21:9
|
21 | done = true;
| ^^^^^^^^^^^ cannot assign
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:19:23
|
19 | a.perform_for_all(|v| {
| _______________________^
20 | | println!("value: {:?}", v);
21 | | done = true;
22 | | });
| |_____^
I have a list of loaded objects and a list of objects in a database. I need a function that takes a closure and executes it on the loaded objects and if we don't have the objects in the list, execute it on a list of objects from the database.
That function looks like:
pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
F: Fn(&mut GameMatch),
{
self.perform_for_all_matches(
|m| {
// runtime list
if let Game::Match(ref mut gm) = *m {
if gm.match_stamp().mark == mark {
f(gm);
}
}
},
None,
);
// if we have called `f` above - don't execute lines below.
let tx = self.match_tx.clone();
GamesDatabase::perform_for_match_with_mark(mark, |ms| {
// database
self.perform_for_all_matches(
|m| {
if let Game::Match(ref gm) = *m {
if gm.match_stamp().id == ms.id {
f(&mut GameMatch::new_with_match_stamp(
tx.clone(),
ms.clone(),
gm.needs_server_set,
gm.server_id,
))
}
}
},
None,
);
});
}
We have to operate on objects from the database only if we were unable to find them in runtime list. That is why I decided to make a variable which says "we already found these objects in the list, leave the database alone".

Change your perform_for_all function to use FnMut instead of Fn:
fn perform_for_all<F>(&mut self, mut f: F)
where
F: FnMut(&mut u64),
{
for mut i in &mut self.vec {
f(&mut i);
}
}
As Peter said, there is some compiler magic going on.
The signature for Fn::call is:
extern "rust-call" fn call(&self, args: Args) -> Self::Output
This takes an immutable reference to self, which is why you can't modify any of the captured variables.
The signature for FnMut::call_mut lets you mutate variables because it takes &mut self:
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
By changing your closure from Fn to FnMut, you allow it to modify its captured variables, given that the references you pass to it are mutable.

Just to expand a little on SplittyDev's answer.
When you use a closure, the compiler does some magic to let the closure access variables in its environment. Effectively it will create a new struct, whose members are the variables that you tried to access.
It's not exactly this (which won't actually compile), but it's a reasonable approximation conceptually:
struct Closure_1 {
done: bool
}
impl FnMut<&mut u64> for Closure_1 {
fn call_mut(&mut self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true;
}
}
And when you call it, those variables will be borrowed or copied (or moved if you use move keyword).
let mut c1 = Closure_1 { done : done };
a.perform_for_all(|v| c1.call(&v));
done = c1.done;
When the closure modifies its environment, it cannot be a Fn because it must also mutate the variables on itself:
impl Fn<&mut u64> for Closure_1 {
fn call(&self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true; // Can't do this because self is not a mutable ref
}
}
See The Rust Programming Language section on closures and their environment for more information.

Related

Cannot borrow `*self` as mutable more than once at a time when using an iterator

I'm trying to learn rust making a game with SDL2. I have a struct GameEngine which has ownership of some variables to control the game state.
The method GameEngine::run() is responsible to manage the game loop. I want this method to do 2 things:
Check if some event is related to closing the game and in this case break the loop
For any other kind of event I want to call a method GameEngine::handle_event() to handle it
The problem is that the compiler is refusing to accept my code telling me I'm trying to borrow self as mutable more than once. The first borrow happen on this line:
let event_poll_iterator = self.event_pump.poll_iter();
and the second on this:
self.handle_event(event);
As I'm a newbie in Rust, I'm getting stuck in this error.
The complete code:
pub mod engine {
use std::time::Duration;
use sdl2::{EventPump, Sdl};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::render::WindowCanvas;
fn get_canvas(sdl_context: &Sdl) -> WindowCanvas {
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
.window("SDL2 Snake Game", 800, 600)
.position_centered()
.opengl()
.build()
.map_err(|e| e.to_string()).unwrap();
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string()).unwrap();
canvas.set_draw_color(Color::BLACK);
canvas
}
pub struct GameEngine {
context: Sdl,
event_pump: EventPump,
canvas: WindowCanvas,
}
impl GameEngine {
pub fn new() -> Self {
let context = sdl2::init().unwrap();
let canvas = get_canvas(&context);
let event_pump = context.event_pump().unwrap();
GameEngine { context, canvas, event_pump }
}
fn redraw(&mut self) {
self.canvas.clear();
self.canvas.present();
}
fn handle_event(&mut self, event: Event) {
todo!()
}
pub fn run(&mut self) {
'game_loop: loop {
let event_poll_iterator = self.event_pump.poll_iter();
for event in event_poll_iterator {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'game_loop,
_ => {
self.handle_event(event);
}
}
}
self.redraw();
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
}
}
}
}
Edit
I could reproduce the same problem (I think) with a much smaller example:
struct List {
v: Vec<u32>
}
impl List {
fn increment(&mut self, x: &mut u32) {
*x += 1;
}
fn iter(&mut self) {
for x in &mut self.v {
self.increment(x);
}
}
}
fn main() {
let mut list = List { v: vec![1, 2, 3] };
list.iter();
assert!(list.v == vec![2, 3, 4]);
}
Error log:
λ cargo run
Compiling rustlings v4.7.1 (/home/luizalabs/repositories/rust/rustlings)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:12:13
|
11 | for x in &mut self.v {
| -----------
| |
| first mutable borrow occurs here
| first borrow later used here
12 | self.increment(x);
| ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `rustlings` due to previous error
The problem is, self.handle_event could modify whatever you are iterating over (in this case event_poll_iterator). If you are modifying what the iterator is iterating over, you might want to consider cloning the iterator. If self.handle_event isn't modifying the iterator, you have to show the borrow checker that you are not modifying the iterator. One option is to inline self.handle_event. Another option is to pass whatever you are modifying as mutable to self.handle_event. Here is a simple example of what is going on:
#[derive(Debug)]
struct Point {
x: i32,
y: i32
}
struct Points {
points: Vec<Point>,
num_points: usize
}
impl Points {
fn bar(&mut self, point: &mut Point) {
println!("{:?}", point)
}
fn foo(&mut self) {
for p in &mut self.points {
self.bar(p);
}
}
}
Inlining would change foo as such:
fn foo(&mut self) {
for p in &mut self.points {
println!("{:?}", p); // modified line
}
}
Tried to simplify your example
fn main() {
let i: i32 = 4326;
let b = i.to_le_bytes();
for i in 0..4 {
println!("{}", b[i]);
}
}
pub struct GameEngine {
event_pump: EventPump,
}
pub struct EventPump {
}
impl EventPump {
pub fn poll_iter(&mut self) -> Vec<i32> {
vec![0, 1, 2]
}
}
impl GameEngine {
pub fn new() -> Self {
GameEngine {
event_pump: EventPump { },
}
}
fn redraw(&mut self) {
}
fn handle_event(&mut self, _event: i32) {
todo!()
}
pub fn run(&mut self) {
loop {
let ep = self.event_pump.poll_iter();
let event_poll_iterator = ep.iter();
for event in event_poll_iterator {
match event {
_ => {
self.handle_event(*event);
}
}
}
self.redraw();
}
}
}
Hope without losing sense. Seems it compiled ok.
It changes Iter to vector instance but I'm not sure if that matters.

Trouble with digraphs: cannot borrow as mutable

I created a library to deal with digraphs: nodes that link (reference counted) to zero or one other nodes (as in linked lists, but in a digraph a node can be linked to by more than one node).
I am trying to use my library to create a list with a current node:
struct ListWithPointer<'a> {
pub nodes: DigraphNodeRef<String>,
pub current_node: Option<&'a mut DigraphNodeRef<String>>,
}
current_node points to a link in the list.
Now I am trying to move current node to the next element of the list (or to the beginning if the list ended):
fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
if this.current_node.is_some() {
this.current_node.iter_mut().for_each(|a| {
(*a).as_rc_mut().iter_mut()
.for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
});
} else {
this.current_node = Some(&mut this.nodes);
}
}
but whatever I do, it fails with an error like:
error[E0500]: closure requires unique access to `this.current_node` but it is already borrowed
--> src/lib.rs:150:51
|
148 | fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
| -- lifetime `'a` defined here
149 | if this.current_node.is_some() {
150 | this.current_node.iter_mut().for_each(|a| {
| ---------------------------- ^^^ closure construction occurs here
| |
| borrow occurs here
| argument requires that `this.current_node` is borrowed for `'a`
151 | (*a).as_rc_mut().iter_mut()
152 | .for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
| ----------------- second borrow occurs due to use of `this.current_node` in closure
Help to rewrite without errors.
Here is the library code:
use std::sync::Arc;
#[derive(Clone)]
pub struct DigraphNode<T> {
pub next: DigraphNodeRef<T>, // I made it `pub` to be able `item.next.next()` to remove an item from the middle.
data: T,
}
impl<T> DigraphNode<T> {
fn new(next: DigraphNodeRef<T>, data: T) -> Self {
Self { next, data }
}
}
pub struct DigraphNodeRef<T> {
rc: Option<Arc<DigraphNode<T>>>,
}
impl<T> DigraphNodeRef<T> {
pub fn new() -> Self {
Self {
rc: None
}
}
pub fn from_node(value: DigraphNode<T>) -> Self {
Self::from(Some(Arc::new(value)))
}
pub fn from(rc: Option<Arc<DigraphNode<T>>>) -> Self {
Self {
rc
}
}
pub fn as_rc(&self) -> &Option<Arc<DigraphNode<T>>> {
&self.rc
}
pub fn as_rc_mut(&mut self) -> &mut Option<Arc<DigraphNode<T>>> {
&mut self.rc
}
pub fn is_none(&self) -> bool {
self.rc.is_none()
}
pub fn remove(&mut self) -> bool {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
true
} else {
false
}
}
pub fn prepend(&mut self, value: T) -> Self {
let new_node = DigraphNode::new(self.clone(), value);
let new_node_ref = DigraphNodeRef::from_node(new_node);
*self = new_node_ref.clone();
new_node_ref
}
pub fn node(&self) -> Option<DigraphNode<T>>
where T: Clone
{
self.rc.clone().map(|node| (*node).clone())
}
/// TODO: Should return a reference.
pub fn data(&self) -> Option<T>
where T: Clone
{
self.rc.clone().map(|node| (*node).data.clone())
}
pub fn values(self) -> DigraphNodeValuesIterator<T> {
DigraphNodeValuesIterator {
underlying: self.clone()
}
}
}
impl<T> Clone for DigraphNodeRef<T> {
fn clone(&self) -> Self {
Self { rc: self.rc.clone() }
}
}
impl<T> Iterator for DigraphNodeRef<T> {
type Item = Arc<DigraphNode<T>>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
Some(rc.clone())
} else {
None
}
}
}
pub struct DigraphNodeValuesIterator<T> {
underlying: DigraphNodeRef<T>,
}
impl<T: Clone> Iterator for DigraphNodeValuesIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.underlying.next().map(|node| node.data.clone())
}
}
In Rust the mutable access is ensured to be exclusive, i.e. if you hold a reference, some other code can't grab a mutable reference.
Problem is this line:
this.current_node.iter_mut().for_each(...)
It grabs a mutable access to current_node, so it can't regain it again down the line.
Not to mention that iterating over Option is a strange decision.
If you want to move current_node to a different place, I'd try to reorganize your code such that reads are separate from writes, and they are performed in a sequence, instead of trying to do it in one go:
// detach the current_node for moving
if let Some(current_node_to_move) = this.current_node.take() {
let new_current_node_ref: &mut ... = ... // find new location logic
new_current_node_ref.replace(current_node_to_move);
} else {
...
}
Here in line 1 it does a write None update to current_node via this, but immediately relinquishes the mutable reference. Line 2 does a read (search), but also grabs a mutable reference to a new location. Line 3 writes to this location.
To get the linked list implementation right, I recommend https://rust-unofficial.github.io/too-many-lists/

Is there a way to tell rustc when is is being too conservative about certain borrows?

I'm playing around with building a very simple stack based evaluator in Rust and I've come up against an odd situation where I think the borrow checker is being too conservative:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
type Op = Box<dyn Fn(&mut Evaluator) -> Result>;
type OpTable = HashMap<String, Op>;
pub struct Evaluator {
stack: Vec<Value>,
ops: OpTable,
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Evaluator {
fn add(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y + x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
fn sub(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y - x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: OpTable = HashMap::new();
ops.insert("+".to_string(), Box::new(Evaluator::add));
ops.insert("-".to_string(), Box::new(Evaluator::sub));
Evaluator { stack, ops }
}
pub fn eval(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
// user definition
if let (Some(&":"), Some(&";")) = (symbols.first(), symbols.last()) {
if symbols.len() > 3 {
let statement = symbols[2..symbols.len() - 1].join(" ");
self.ops.insert(
symbols[1].to_string().to_ascii_lowercase(),
Box::new(move |caller: &mut Evaluator| caller.exec(&statement)),
);
return Ok(());
} else {
return Err(Error::InvalidWord);
}
}
self.exec(input)
}
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) { // <--------------errors here
f(self)?; // <----------------------------|
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +");
println!("{:?}", e.stack);
e.eval(": plus-1 1 + ;");
e.eval("4 plus-1");
println!("{:?}", e.stack);
}
I'm getting:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:77:21
|
76 | if let Some(f) = self.ops.get(&s) {
| -------- immutable borrow occurs here
77 | f(self)?;
| -^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
For more information about this error, try `rustc --explain E0502`.
error: could not compile `evaluator` due to previous error
I believe this is because taking part of the hashmap (f) borrows all of self immutably, then I'm passing self mutably to f(). However, there is no real conflict here (I think).
I'm able to get around this by actually removing and reinserting the value:
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if self.ops.contains_key(&s) {
let f = self.ops.remove(&s).unwrap();
if let Err(e) = f(self) {
self.ops.insert(s, f);
return Err(e);
}
self.ops.insert(s, f);
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
But this feels hacky and is a lot more verbose and inefficient. Am I missing something? Is there a way to tell the compiler the first version is ok?
The compiler is entirely correct, and so is your explanation: The call to get() needs a borrow on self.ops to return an &Op of the same lifetime. You then try to call that FnMut with a mutable borrow of self; this mutable borrow of self aliases with the immutable borrow on self.ops, and in theory it would be possible for an implementation of this FnMut to modify that borrowed Op through self, which is not allowed. The compiler prevented a situation where mutation occurs through an aliased pointer.
This situation often occurs when passing &mut self around, as immutable borrows on members of self which result in more borrows (&self.ops.get() has the same lifetime as &self) "lock" all of self.
While your second example is cumbersome, it is at least correct as proven by the compiler: By removing Op from the hashtable, the FnMut can't reach itself through self anymore, and mutation while aliasing is prevented.
A better approach is usually to avoid taking &mut self as an argument (&mut self as in &mut Executor).

Calling method on &mut self after accessing property in Rust [duplicate]

This question already has answers here:
Borrowing references to attributes in a struct
(2 answers)
Passing mutable self reference to method of owned object
(2 answers)
Why does calling a method on a mutable reference involve "borrowing"?
(2 answers)
Rust borrow mutable self inside match expression
(1 answer)
How to end a borrow in a match or if let expression?
(2 answers)
Closed 5 years ago.
I need to match on an optional value that is on self, from a method, and based on that match, call a method on self that takes self mutably. I'm trying to do a pretty high-performance game, so as much as I'd like to dispense with mutability, I can't in this situation: the methods really do need to access the struct mutably, and they really do need to be dispatched based on the structs properties. Here is an MVCE:
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
if let Some(ref b) = self.bar {
match b {
&Baz::A => self.do_a(fizz),
&Baz::B => self.do_b(fizz + 2),
&Baz::C => self.do_c(fizz + 1),
}
}
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let foo = Foo { bar: Some(Baz::A) };
foo.dostuff(3);
}
And here is the playground.
error[E0502]: cannot borrow `*self` as mutable because `self.bar.0` is also borrowed as immutable
--> src/main.rs:14:28
|
12 | if let Some(ref b) = self.bar {
| ----- immutable borrow occurs here
13 | match b {
14 | &Baz::A => self.do_a(fizz),
| ^^^^ mutable borrow occurs here
...
18 | }
| - immutable borrow ends here
I thought I'd made my peace with the borrow checker, but apparently not: I have no idea how to fix this, although I do know why this is happening. I would appreciate it if somebody explained how to avoid this in the future.
If you care about the references, as far as I know, Rust's rules forbid you from having such code. You have to either:
Copy or Clone your bar object and unwrap as how as you want.
Add some flag and make the code not have multiple references to the object. For example, add two variables which will tell you to what to do. You match your enum, set these variables and then you match these variables. This is less-useful than the first item here but this is a solution also.
Be more functional-like:
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
let (method, arg) = match self.bar {
Some(ref b) => {
match b {
&Baz::A => (Self::do_a as fn(&mut Self, i32)>, fizz),
&Baz::B => (Self::do_b as fn(&mut Self, i32)>, fizz + 2),
&Baz::C => (Self::do_c as fn(&mut Self, i32)>, fizz + 1),
}
},
None => return,
};
method(self, arg);
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let mut foo = Foo { bar: Some(Baz::A) };
foo.dostuff(3);
}
By doing so you return a method which you wanna call with it's argument, so you just call what you need to. I am pretty sure this solution can be rewritten without using Box but just references to a method but I don't know how.
You can unwrap the Option(Baz) within the match instead of using if
let..
Declare foo as mutable
Here is the code ...
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
match self.bar {
Some(Baz::A) => self.do_a(fizz),
Some(Baz::B) => self.do_b(fizz + 2),
Some(Baz::C) => self.do_c(fizz + 1),
None => {},
}
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let mut foo = Foo { bar: Some(Baz::B) };
foo.dostuff(3);
}

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?
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;
}
}
}
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.)

Resources