2013-12-12 4 views
3

В 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"); 
} 

код не будет даже компиляции. rust test думает, что есть ошибка во втором assert_eq:

error: use of partially moved value: strs

Это несколько нелогичным. Я имею в виду, какие бы эффекты ни имели первые assert_eq, они должны быть полностью вне сферы действия, когда выполнение достигает второго assert_eq. Если, конечно, он не появляется за сценой. Имеет ли это?

Если нет, то почему эта загадочная ошибка? Надеюсь, нет никаких фундаментальных недостатков в моем понимании указателей ржавчины.

ответ

6

В Rust 0.8, assert_eq! определяется как

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); 
      } 
     } 
    ) 
) 

Отметим здесь, что он перемещает оба аргумента в местные LET-привязок given_val и expected_val. Это то, что вызывает вашу ошибку.

В текущем главном это исправлено. assert_eq! теперь принимает ссылки на аргументы:

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) 
      } 
     } 
    ) 
) 

Это означает, что он больше не перемещает его аргументы, которые исправляет ошибку.

Если вам нужно придерживаться ржавчины 0,8, вы можете изменить это на assert!() и выполнить сравнение напрямую, что позволит избежать движения. Но моя рекомендация - обновить до последнего мастера.

3

Он работает на Git master. Должна быть ошибка, которая была исправлена ​​после того, как 0,8 был разрезан. В общем, выпущенные версии не ограничены, чтобы быть особенно стабильными до выпуска - они по сути являются просто снимками.

Определение макроса assert_eq!, в libsyntax, принимает ссылки на аргументы, поэтому аргументы не должны перемещаться, и вы можете использовать их после вызова макроса.

Если вы нашли другую ошибку, попробуйте скомпилировать мастера, если сможете, или просто создайте новый issue.

Смежные вопросы