Wrong ownership with Tuple matching

  enum T {
    A(Vec<u8>),
    B(Vec<u8>)
  }
  let a = T::A(Vec::new());
  let b = T::B(Vec::new());
  if let (T::A(a),T::B(b)) = (a,b) {
    drop(a);
    drop(b);
  }else {
    drop(a);
    drop(b);
  }

Codes above cannot be passed, with errmessage of use of moved value a,b.

  enum T {
    A(Vec<u8>),
    B(Vec<u8>)
  }
  let a = T::A(Vec::new());
  let b = T::B(Vec::new());
  if let T::A(n) = a {
    drop(n);
  }else {
    drop(a);
  }

This makes correct. Why?

Because the expression you use to create your tuple (a, b) moves a and b into the tuple. The tuple takes ownership of the values. You can't use a or b after creating your tuple, because they got moved. If you want to prevent moving a and b you can instead use references when creating your tuple, changing its data type from (T, T) to (&T, &T):

  if let (T::A(a),T::B(b)) = (&a, &b) {
    drop(a);
    drop(b);
  }else {
    drop(a);
    drop(b);
  }

Playground.

(of course the code doesn't make much sense, dropping references does nothing).

1 Like

I'm using drop to emulate of taking ownership.

Finally I got a interesting way to deal it

  enum T {
    A(Vec<u8>),
    B(Vec<u8>)
  }
  let a = T::A(Vec::new());
  let b = T::B(Vec::new());
  if let T::A(a) = a {
    if let T::B(b) = b {
      drop(a);
      drop(b);
    }else {
      // do something
    }
  }else {
    drop(a);
    drop(b)
  }

Rude but effective

So the behavior of (a,b) already took the ownership, I think it is correct. Thanks for your patience!

You can just use references in the match like @jofas illustrated without shadowing the original a, b variables.

    if let (T::A(_), T::B(_)) = (&a, &b) {
        drop(a);
        drop(b);
    } else {
        drop(a);
        drop(b);
    }
1 Like