Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust: use of partially moved values

Tags:

rust

In Rust 0.8:

struct TwoStr {
  one: ~str,
  two: ~str,
}

#[test]
fn test_contents() {
  let strs = TwoStr {
    one: ~"pillar",
    two: ~"post",
  };

  assert_eq!(strs.one, ~"pillar");
  assert_eq!(strs.two, ~"post");
}

The code won't even compile. The rust test thinks there's an error in the second assert_eq:

error: use of partially moved value: strs

It is somewhat counter-intuitive. I mean, whatever effects the first assert_eq may have, it should be well out of the scope when the execution reaches the second assert_eq. Unless of course, it does some spawn behind the scene. Does it?

If not, why this mysterious error? Hopefully there's no fundamental flaws in my understanding of Rust pointers.

like image 948
edwardw Avatar asked Jan 30 '26 08:01

edwardw


1 Answers

In Rust 0.8, assert_eq! is defined as

macro_rules! assert_eq (
    ($given:expr , $expected:expr) => (
        {
            let given_val = $given;
            let expected_val = $expected;
            // check both directions of equality....
            if !((given_val == expected_val) && (expected_val == given_val)) {
                fail!(\"assertion failed: `(left == right) && (right == \
                left)` (left: `%?`, right: `%?`)\", given_val, expected_val);
            }
        }
    )
)

Note here that it moves both arguments into local let-bindings given_val and expected_val. This is what is causing your error.

In current master, this has been fixed. assert_eq! now takes references to the arguments:

macro_rules! assert_eq (
    ($given:expr , $expected:expr) => (
        {
            let given_val = &($given);
            let expected_val = &($expected);
            // check both directions of equality....
            if !((*given_val == *expected_val) &&
                 (*expected_val == *given_val)) {
                fail!("assertion failed: `(left == right) && (right == left)` \
                       (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
            }
        }
    )
)

This means that it no longer moves its arguments, which fixes your error.

If you need to stick with rust 0.8, you can change this to using assert!() instead and do the comparison directly, which will avoid the move. But my recommendation is to upgrade to latest master.

like image 95
Lily Ballard Avatar answered Feb 02 '26 00:02

Lily Ballard