I have a struct App
:
struct App {
cmd: Command
}
that owns a command of type Command
:
enum Command {
Cmd1 { flag: bool }
}
(I use StructOpt to derive a command line interface from that.)
To execute the right command I have a function like this:
impl App {
fn execute(&mut self) {
match &self.cmd {
Command::Cmd1 { flag } => self.do_cmd1(*flag)
};
}
}
where I handle the actual execution in an extra function do_cmd1(&mut self, flag: bool)
to keep execute
clean. However, this does not work since in self.do_cmd1(*flag)
I borrow self
as mutable and also as immutable via *flag
which belongs to cmd
which in turn belongs to self
.
My question is: What would be the proper way to access flag
in do_cmd1
that respects the borrowing rules?
Clarification: I need this to also work for things like
enum Command {
Cmd2 { text: String }
}
where the variant's field is not Copy
.
If you move or copy the flag out of self
before calling do_cmd1
, the borrows don't need to overlap.
fn execute(&mut self) {
match self.cmd {
Command::Cmd1 { flag } => self.do_cmd1(flag),
};
}
The only changes are removing the &
from &self.cmd
and the *
from *flag
.
The above works because bool
is a Copy
type. For types that are not Copy
, you will need to do some extra work to ensure the borrows do not overlap, as in these related questions:
This is a solution I have come up with, although I think there should be a better one:
Extend the Command
enum in the following way:
impl Command {
fn get_cmd1_flag(&self) -> Option<bool> {
match &self {
Command::Cmd1 { flag } => Some(*flag),
_ => None
}
}
}
Then, alter the signature of do_cmd1
to do_cmd1(&mut self)
(ie remove the flag
argument). To access flag
inside of do_cmd1
you can just call self.cmd.get_cmd1_flag()
and handle the Option
. Together with proper return types and use of the ?
operator this is even quite comfortable to write.
What I dislike about this solution is that you somehow implement an own layer of type checking, which is why I think there should be a more elegant way. But at least this works.
Does do_cmd1
really need to be a method of App
?
In other words: You may be able to separate the cmd
and the "other", non- cmd
part (let's call it Executor
) and put them in different fields of your struct:
struct App {
cmd: Command
exe: Executor
}
impl App {
fn execute(&mut self) {
match &self.cmd {
Command::Cmd1 { flag } => self.exe.do_cmd1(*flag)
};
}
}
This way, it is clear which parts of self
are actually borrowed mutably.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.