How to correct this code, not wanna use clone or copy

use rand::prelude::*;


#[derive(Debug, Default)]
pub struct Watcher {
    pats: Vec<String>,
    trng: ThreadRng,
}

impl Watcher {
    pub fn watch(&self, act: &mut dyn FnMut() -> Result<(), Box<dyn Error>>) -> Result<(), Box<dyn Error>>{
        self.pats
            .iter()
            .try_for_each(|_| act())
    }
}

fn main() {
    let mut watcher = Watcher::default();
    let mut clsr = || {
        watcher.trng.next_u32();
        Ok(())
    };
    
    watcher.watch(&mut clsr);
}

Error while compiling

Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `watcher` as immutable because it is also borrowed as mutable
  --> src/main.rs:27:5
   |
22 |     let mut clsr = || {
   |                    -- mutable borrow occurs here
23 |         watcher.trng.next_u32();
   |         ------------ first borrow occurs due to use of `watcher.trng` in closure
...
27 |     watcher.watch(&mut clsr);
   |     ^^^^^^^^^^^^^^---------^
   |     |             |
   |     |             mutable borrow later used here
   |     immutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to previous error

I want to create a filewatcher. 'pat' vector contains patterns to watch. trng is notify filewatcher. I am writing act method for watching/unwatching according a flag in single method, otherwise i have to write two method with duplicated code.

I already know about lifetimes and tried several workarounds but none worked and I dont wanna use 'Clone' or 'Copy'

I hope its clear enough

note: rand is used due to rust playground doesnt allow notify

Please format your code properly and ask an actual question with the essential details:

  • what is this supposed to do?
  • what's wrong? (are you getting compile errors, runtime errors, anything else?)

You can't just dump a bunch of code without context and expect people to guess and solve your problem.

2 Likes

I'd probably pass the field of Watcher the closure needs access to as an argument:

use rand::prelude::*;
use std::error::Error;

use std::path::PathBuf;

#[derive(Debug, Default)]
pub struct Watcher {
    pats: Vec<PathBuf>,
    trng: ThreadRng,
}

impl Watcher {
    pub fn watch(
        &mut self,
        act: impl Fn(&mut ThreadRng, &PathBuf) -> Result<(), Box<dyn Error>>,
    ) -> Result<(), Box<dyn Error>> {
        self.pats
            .iter()
            .try_for_each(|pat| act(&mut self.trng, pat))
    }
}

fn main() {
    let mut watcher = Watcher::default();

    watcher
        .watch(|notifier, _pattern| {
            notifier.next_u32();
            Ok(())
        })
        .unwrap();
}

Playground.

thanks, that'll do the job

You probably could also make your callback return a bool and when it is true you notify. Don't know if this is how your notification logic works though. That way you can keep your notifier hidden from the closure and make your interface even better IMO:

use rand::prelude::*;
use std::error::Error;

use std::path::PathBuf;

#[derive(Debug, Default)]
pub struct Watcher {
    pats: Vec<PathBuf>,
    trng: ThreadRng,
}

impl Watcher {
    pub fn watch(
        &mut self,
        act: impl Fn(&PathBuf) -> Result<bool, Box<dyn Error>>,
    ) -> Result<(), Box<dyn Error>> {
        self.pats
            .iter()
            .try_for_each(|pat| {
                if act(pat)? {
                    self.trng.next_u32();
                }
                
                Ok(())
            })
    }
}

fn main() {
    let mut watcher = Watcher::default();

    watcher
        .watch(|_pattern| {
            Ok(true)
        })
        .unwrap();
}

Playground.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.