# Confusing @ Pattern matching

**URL:** <https://users.rust-lang.org/t/confusing-pattern-matching/97271>\
**Category:** help\
**Created:** [July 21, 2023, 7:02am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271 "2023-07-21T07:02:58Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![TOETOE55](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/toetoe55/32/35203_2.png) [@TOETOE55](https://users.rust-lang.org/u/TOETOE55)\
**Post date:** [July 21, 2023, 7:02am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/1 "2023-07-21T07:02:58Z")

</div>

Why does the following code compile, but not after removing the comment.

```rust
fn main() {
    let msg = Message::World { id: 123 };
    match msg {
        x @ Message::World { id, .. } => println!("{x:?} {id}"),
        x => println!("{x:?}"),
    }
}

#[derive(Debug)]
enum Message {
    // Hello { a: i32 },
    World { id: i32 },
}

```

> **[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dca3afd98e3f9f0b6eee0bdb190276f6)**
>
> A browser interface to the Rust compiler to experiment with the language

---

<div class="post-metadata">

**Author:** ![hax10](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/hax10/32/33598_2.png) [@hax10](https://users.rust-lang.org/u/hax10)\
**Post date:** [July 21, 2023, 7:39am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/2 "2023-07-21T07:39:05Z")

</div>

According to the [Rust docs](https://doc.rust-lang.org/std/keyword.ref.html):

> By default, [`match`](https://doc.rust-lang.org/std/keyword.match.html) statements consume all they can, which can sometimes be a problem, when you don’t really need the value to be moved and owned.

i.e. in this piece of code

```rust
match msg {
    x @ Message::World { id, .. } => println!("{x:?} {id}"),
    x => println!("{x:?}"),
}

```

ownership of the enum `msg: Message` is moved into the first arm and `msg` will be dropped after you destructure it and extract your `id`. This means `msg` is no longer available in other match arms.

This doesn't cause a problem when your enum only has one variant, because the second match arm is unreachable, but when you add the `Hello` variant to the `Message` enum, the compiler will complain about a value being used after it's moved.

One possible solution is to match `msg` by reference rather than take ownership, i.e.

```rust
match msg {
    ref x @ Message::World { id, .. } => println!("{x:?} {id}"),
    ref x @ Message::Hello { a, .. } => println!("{x:?} {a}"),
}

```

Another would be derive `Copy` and `Clone` on your enum, which would allow Rust to make a copy of `msg` and take ownership of the copy.

---

<div class="post-metadata">

**Author:** ![TOETOE55](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/toetoe55/32/35203_2.png) [@TOETOE55](https://users.rust-lang.org/u/TOETOE55)\
**Post date:** [July 21, 2023, 8:59am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/3 "2023-07-21T08:59:10Z")

</div>

> [@hax10](#):
>
> > which can sometimes be a problem, when you don’t really need the value to be moved and owned.

Nop, borrow checks between different branches in pattern matching should not affect each other.

---

<div class="post-metadata">

**Author:** ![Heliozoa](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/heliozoa/32/16524_2.png) [@Heliozoa](https://users.rust-lang.org/u/Heliozoa)\
**Post date:** [July 21, 2023, 9:18am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/4 "2023-07-21T09:18:58Z")

</div>

It seems that with an irrefutable pattern, the compiler does a partial move, but with a refutable pattern it doesn't. Not sure why, maybe someone with more compiler knowledge can explain. With a partial move, only the `id` is copied out and there's no problem accessing the enum afterwards, but without a partial move it's a bit like both sides of the @ are trying to take ownership of the whole struct and that's not allowed.

```rust
fn main() {
    if let e @ E::A(s) = { E::A(String::new()) } {}
}

enum E {
    A(String),
    B,
}

```

```rust
error[E0382]: use of moved value
 --> src/main.rs:2:21
  |
2 | if let e @ E::A(s) = { E::A(String::new()) } {}
  | - ^ ----------------------- move occurs because value has type `E`, which does not implement the `Copy` trait
  | | |
  | | value used here after move
  | value moved here

```

vs

```rust
fn main() {
    if let e @ E::A(s) = { E::A(String::new()) } {}
}

enum E {
    A(String),
}

```

```rust
error[E0382]: use of partially moved value
 --> src/main.rs:2:12
  |
2 | if let e @ E::A(s) = { E::A(String::new()) } {}
  | ^ - value partially moved here
  | |
  | value used here after partial move

```

---

<div class="post-metadata">

**Author:** ![TOETOE55](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/toetoe55/32/35203_2.png) [@TOETOE55](https://users.rust-lang.org/u/TOETOE55)\
**Post date:** [July 21, 2023, 11:44am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/6 "2023-07-21T11:44:03Z")

</div>

I seem that "the matching order" was different .

For irrefutable @ pattern `x @ World { id: y, .. }`, it will be matched as `World { id, .. }` first, copy it `id` to `y`, then bind(move) it to `x`.

But for normal pattern matching, it will firstly bind it to `x`, then match `World { id: y, .. }`(match after move).

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/quinedot/32/17693_2.png) [@quinedot](https://users.rust-lang.org/u/quinedot)\
**Post date:** [July 21, 2023, 6:57pm UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/7 "2023-07-21T18:57:49Z")

</div>

Looks to be the issue below. Note that the title is inaccurate: it's a Rust 1.56+ feature, not an edition specific feature. [How the feature should work is underspecified IMO.](https://github.com/rust-lang/rust/issues/65490#issuecomment-841999009)

> <https://github.com/rust-lang/rust/issues/90368>
>
> I tried the new "binding to sub-patterns" feature in the 2021 edition and it did… not work as I expected, or consistently. \[Here's a playground link\](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4a14b694497d8cece3bacb75fcdba5bf).
> 
> First, I tried:
> 
> \`\`\`rust
> // NOT copy!
> \#\[derive(Debug)\]
> enum One {
> A,
> B(bool),
> }
> 
> fn main() {
> let a = One::B(true);
>     
> match a {
> One::A =\> println!("A"),
> other @ One::B(success) =\> {
> println!("{:?}", other);
> println!("{}", success);
> }
> }
> }
> \`\`\`
> 
> I expected that even though the wrapping enum is not \`Copy\`, because the nested \`bool\` value \*is\*, it would be copied into \`success\`. However, I get the error:
> 
> \`\`\`text
> error\[E0382\]: use of moved value: \`a\`
> --\> src/main.rs:13:24
> |
> 9 | let a = One::B(true);
> | - move occurs because \`a\` has type \`One\`, which does not implement the \`Copy\` trait
> ...
> 13 | other @ One::B(success) =\> {
> | ---------------^^^^^^^-
> | | |
> | | value used here after move
> | value moved here
> 
> For more information about this error, try \`rustc --explain E0382\`.
> error: could not compile \`playground\` due to previous error
> \`\`\`
> 
> Comparing this to the \[example in the release notes\](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html#new-bindings-in-binding--pattern), where there's a non-\`Copy\` container (\`Matrix\`) with a \`Copy\`-able field (\`row\_len\`), I don't see why it shouldn't work the same way.
> 
> Strangely (I think), if I \[remove the \`A\` variant\](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a77830e71e9a27ac9a3ee24062959f79), it works. So infallible patterns allow this.
> 
> It will also work if I do \`ref other @ One::B(success)\`, but then I can't take ownership of \`other\`.
> 
> Rust version: \`rustc 1.56.0 (09c42c458 2021-10-18)\`  
> Platform: Ubuntu 21.04  
> Installed via Rustup

---

<div class="post-metadata">

**Author:** ![vague](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/vague/32/21401_2.png) [@vague](https://users.rust-lang.org/u/vague)\
**Post date:** [July 22, 2023, 5:27am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/8 "2023-07-22T05:27:08Z")

</div>

> [@quinedot](#):
>
> [How the feature should work is underspecified IMO.](https://github.com/rust-lang/rust/issues/65490#issuecomment-841999009)

> as a result, this feature (and the borrow checking rules around it) is very [well tested](https://github.com/rust-lang/rust/tree/master/src/test/ui/pattern/bindings-after-at).

For the linked comment\[1\], I would rather say the feature is not well tested (or very little specified).

And I raised [a type inconsistency problem on `@ binding`](https://github.com/rust-lang/rust/issues/101510) which was closed as not a bug. [Rust Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6fdf5d61b5081c9c7e2df62df05317a7)

* * *

1. and a bit annoying to see a dead link there ☹

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [October 20, 2023, 5:27am UTC](https://users.rust-lang.org/t/confusing-pattern-matching/97271/9 "2023-10-20T05:27:41Z")

</div>

Closed on October 20, 2023, 5:27am UTC

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.
