Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Matching on structopt commands and using values after move
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. ```rust 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](https://doc.rust-lang.org/reference/patterns.html). ``` 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 ``` ```rust 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`](https://doc.rust-lang.org/std/clone/trait.Clone.html), 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](https://doc.rust-lang.org/std/marker/trait.Copy.html) ```rust fn main() -> Result<()> { let opt = Opt::from_args(); dbg!(&opt); match opt.cmd { Command::Write { title: _ } => todo!(), } } ```
- Loading branch information