2

So I'm doing this years advent of code and I've come across a borrowing problem:

How to have a struct that accepts closures calling methods from another variable? Here's a minimum example I've managed to come up with. The borrow checker doesn't like that the two closures both borrow values.

If I have a mutex around values then it seems to work but I was hoping for a more elegant solution.

Essentially, I want to have different Brains with different input/output functions where one might just print outputs and another might be adding outputs to a vec.

Playground link.

Actual code where I use it.

struct Brain<I, O>
where
    I: Fn() -> i32,
    O: FnMut(i32),
{
    input: I,
    output: O,
}

impl<I, O> Brain<I, O>
where
    I: Fn() -> i32,
    O: FnMut(i32),
{
    fn new(input: I, output: O) -> Self {
        Brain { input, output }
    }
}

fn runner() {
    let mut values = Vec::new();
    let request_input = || *values.last().unwrap();
    let add_output = |v| values.push(v);

    let _ = Brain::new(request_input, add_output);
}

Zoe
  • 27,060
  • 21
  • 118
  • 148
prscoelho
  • 23
  • 4

1 Answers1

1

You are doing it wrong, you obviously can't do that in rust, you can only have one mutable reference or one and more reference, but not both. Instead of using interior mutability like Mutex or Cell, I advice you do use a trait, for example you could do:

trait Bus {
    fn input(&self) -> i32;
    fn output(&mut self, v: i32);
}

struct Brain<T>
where
    T: Bus,
{
    bus: T,
}

impl<T> Brain<T>
where
    T: Bus,
{
    fn new(bus: T) -> Self {
        Brain { bus }
    }
}

struct MyBus {
    values: Vec<i32>,
}

impl Bus for MyBus {
    fn input(&self) -> i32 {
        *self.values.last().unwrap()
    }

    fn output(&mut self, v: i32) {
        self.values.push(v)
    }
}

fn main() {
    let bus = MyBus { values: Vec::new() };

    let _ = Brain::new(bus);
}

This allow a lot of flexibility.

Stargateur
  • 24,473
  • 8
  • 65
  • 91