0

i have a struct Screen with its implementation

pub struct Screen {
    stdin:  Stdin,
// types are irrelevant
    stdout: MouseStdout,
}

impl Screen {
   // ...
    pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
        &self,
        mut handler: F,
    ) {
        let stdin = stdin();
        for e in stdin.events() {
            let e = e.unwrap();
            match e {
                Event::Key(Key::Ctrl('c')) => break,
                _ => {
                    handler(&e);
                },
            }

        }
    }
}

and usage (which is wrong and know it)

    let mut screen = Screen::new();
    screen.init_screen();

    screen.handle_keys_loop(|event| {
        match event {
            Event::Key(Key::Char('a')) => {
                screen.println("hello there",15, 1, true);
            },
            _ => {}
        }
    });

    screen.end_screen();

the error is

error[E0502]: cannot borrow `screen` as mutable because it is also borrowed as immutable
  --> src/bin/terminal.rs:74:29
   |
74 |       screen.handle_keys_loop(|event| {
   |       -      ---------------- ^^^^^^^ mutable borrow occurs here
   |       |      |
   |  _____|      immutable borrow later used by call
   | |
75 | |         match event {
76 | |             Event::Key(Key::Char('a')) => {
77 | |                 println!("{} {} {} {}", "do something with a", 15, 1, true);
78 | |                 // tried to borrow as mutable
79 | |                 screen.println("hello there",15, 1, true);
   | |                 ------ second borrow occurs due to use of `screen` in closure
...  |
82 | |         }
83 | |     });
   | |______- immutable borrow occurs here

and if i make self mut inside handle_keys_loop to get rid of cannot borrow screen as mutable because it is also borrowed as immutable

    pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
        + &mut self,
        - &self
....

i get this error

error[E0499]: cannot borrow `screen` as mutable more than once at a time
  --> src/bin/terminal.rs:74:29
   |
74 |       screen.handle_keys_loop(|event| {
   |       -      ---------------- ^^^^^^^ second mutable borrow occurs here
   |       |      |
   |  _____|      first borrow later used by call
   | |
75 | |         match event {
76 | |             Event::Key(Key::Char('a')) => {
77 | |                 screen.println("hello there",15, 1, true);
   | |                 ------ second borrow occurs due to use of `screen` in closure
...  |
80 | |         }
81 | |     });
   | |______- first mutable borrow occurs here

what im trying to do: use the method handle_keys_loop of screen and pass screen inside the closure, which is passed to handle_keys_loop. basically, to use screen inside of screen.

how do i achieve that ?

some people told me to use RefCell, but that didnt work out very well, i got BorrowError.

i will use any workaround to just use screen inside the closure which is passed to screen's method.

thanks in advance.

0

2 Answers 2

2

One pattern I use to handle such a situation is to pass self: &mut Self back into the closure from handle and use that inside the closure. A simplified version of your code:

struct Screen {}

struct Event {}

impl Screen {
    fn handle<F: FnMut(&mut Screen, Event)>(&mut self, mut handler: F) {
        handler(self, Event {})
    }

    fn print(&mut self) {}
}

fn main() {
    let mut screen = Screen {};
    screen.handle(|screen, _event| screen.print());
    screen.handle(|screen, _event| screen.print());
}
Sign up to request clarification or add additional context in comments.

1 Comment

yes. that works very well.
1

You can't do what you're trying to do because it violates Rust's rule that you can't mutate a value while something else has access to it.

However, your handle_keys_loop method doesn't even use self which means the &self parameter is redundant. There's no reason to give a function an argument it's not going to use (except when implementing a trait that requires it).

Just remove the argument:

    pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
        mut handler: F,
    ) {

And call it as Screen::handle_keys_loop(|event| { ... }).

Alternatively, make it a free function, external to Screen entirely, since it doesn't depend on Screen in any way.

1 Comment

true. it doesnt use self. it was, but i made some modifications. i would like to keep the self because maybe i will need it in the future, for example to call some other functions of screen on other branches of the match

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.