We can match on opt.cmd
to determine which Command
variants was called. This lets us specify the variants
as match criteria and also destructure the values out
to use them.
let opt = Opt::from_args();
dbg!(&opt);
match opt.cmd {
Command::Write { title } => todo!(),
}
As written, we run into two issues with this code.
One is that we aren't using title
yet. In
destructuring, we can use the placeholder (_
) in our
pattern.
warning: unused variable: `title`
--> src/main.rs:32:26
|
32 | Command::Write { title } => todo!(),
| ^^^^^ help: try ignoring the field: `title: _`
|
= note: `#[warn(unused_variables)]` on by default
fn main() -> Result<()> {
color_eyre::install()?;
let opt = Opt::from_args();
dbg!(opt);
match opt.cmd {
Command::Write { title: _ } => todo!(),
}
}
The second issue is that the opt
variable is moved
before we try to destructure it. If we look at the
compiler output before we fixed the title
issue we
see the value use after move pointing at title
specifically.
error[E0382]: use of moved value
m --> src/main.rs:32:26
|
29 | let opt = Opt::from_args();
| --- move occurs because `opt` has type `Opt`, which does not implement the `Copy` trait
30 | dbg!(opt);
| ---------- value moved here
31 | match opt.cmd {
32 | Command::Write { title } => todo!(),
| ^^^^^ value used here after move
If we look at it after fixing the unused title
,
we see the compiler point at opt.cmd
.
error[E0382]: use of moved value: `opt.cmd`
--> src/main.rs:31:11
|
29 | let opt = Opt::from_args();
| --- move occurs because `opt` has type `Opt`, which does not implement the `Copy` trait
30 | dbg!(opt);
| ---------- value moved here
31 | match opt.cmd {
| ^^^^^^^ value used here after move
This is because opt is moved into the dbg
call because
it doesn't implement the Copy
trait. Now, we could
implement or derive Copy
for Opt
if Command
can
implement Copy
, but we can not implement Copy
for
Command
. This is because String
does not, and can not,
implement Copy
, and we have a String
in our title
.
Without diving into the depths of Copy
, Clone
,
and allocation, there is something we have that already
implements Copy
, so we don't need to.
Shared references implement Copy
.
So instead of passing opt
into dbg!
, and thus using
move semantics (which are the default in Rust), we can
pass a shared reference in: dgb!(&opt)
which lets us
use copy semantics.
The difference between move semantics and copy semantics
in this case is that we can access opt
after passing it
to dbg!
.
Under the hood, both a copy and a move can result in bits being copied in memory, although this is sometimes optimized away. -- Copy
fn main() -> Result<()> {
let opt = Opt::from_args();
dbg!(&opt);
match opt.cmd {
Command::Write { title: _ } => todo!(),
}
}