Reputation: 16715
I am making a bot. When the bot receives a message it needs to check all the commands if they trigger on the message and if yes - perform an action.
So I have a vector of commands (Command
trait) in main struct:
struct Bot {
cmds: Vec<Box<Command>>,
}
Everything is good until I try to make a list of triggered commands and to use them later in (&self mut)
method:
let mut triggered: Vec<Box<command::Command>>;
for c in &self.cmds {
if c.check(&message) {
triggered.push(c.clone());
}
}
Error:
bot.rs:167:44: 167:56 error: mismatched types:
expected `Box<Command>`,
found `&Box<Command>`
(expected box,
found &-ptr) [E0308]
What am I doing wrong here? I tried a lot but nothing helps. Initially I was doing the following:
for c in &self.cmds {
if c.check(&message) {
c.fire(&message, self);
}
}
but it gave me:
bot.rs:172:46: 172:50 error: cannot borrow `*self` as mutable because `self.cmds` is also borrowed as immutable [E0502]
bot.rs:172
c.fire(&message, self);
So I stackoverflowed it and came to solution above.
Upvotes: 0
Views: 652
Reputation: 11177
What am I doing wrong here? I tried a lot but nothing helps. Initially I was doing the following:
for c in &self.cmds { if c.check(&message) { c.fire(&message, self); } }
If the fire
function does not need access to other commands, an option is to temporarily replace self.cmd
with an empty vector:
trait Command {
fn check(&self, message: &str) -> bool;
fn fire(&mut self, bot: &Bot);
}
struct Bot {
cmds: Vec<Box<Command>>,
}
impl Bot {
fn test(&mut self, message: &str) {
use std::mem;
// replace self.cmds with a empty vector and returns the
// replaced vector
let mut cmds = mem::replace(&mut self.cmds, Vec::default());
for c in &mut cmds {
if c.check(message) {
c.fire(self);
}
}
// put back cmds in self.cmds
mem::replace(&mut self.cmds, cmds);
}
}
There are other answers that use this approach.
If fire
does need access to some fields of Bot
, you can pass only the needed fields instead of self
:
c.fire(self.others)
Upvotes: 2