如何交换结构的两个字段

时间:2016-02-26 11:00:07

标签: struct reference rust swap

我开始研究Rust,我正在尝试实现一个简单的一维元胞自动机。我想将自动机状态(Board)表示为包含大小和两个不同向量(相同大小)的结构。我试过了:

struct Board {
    n: usize,
    cur:  Vec<u32>,
    next: Vec<u32>,
}

impl Board {
    fn new(size: usize) -> Board {
        Board {
            n: size,
            cur: vec![0;size],
            next: vec![0;size],
        }
    }
}

到目前为止一切顺利。我也能够改变两种载体。但后来我希望能够交换两个向量(或者更确切地说是它们的引用),例如:

fn swap(&mut self) -> &Board {
    let tmp = self.cur;
    self.cur = self.next;
    self.next = tmp;
    self
}

它失败了,我认为我可以理解cannot move out of borrowed content [E0507]。我也试过了mem::swap,我在类似的标题问题中找到了这个问题而没有成功。

如何让这个例子有效? (由于我是Rust的初学者,请不要犹豫,建议使用不同的数据表示。)

2 个答案:

答案 0 :(得分:4)

正如您所注意到的,mem::swap是要走的路:

fn swap(&mut self) -> &Board {
    std::mem::swap(&mut self.cur, &mut self.next);
    self
}

这很有效。请注意,使用.时,您将取消引用self。因此,虽然self的类型为&mut Board,但self.cur的类型为Vec<u32>。因此,编译器抱怨“摆脱借来的内容”,我们需要额外的&mut

答案 1 :(得分:4)

  

问题是什么?

您在数据中打洞

fn swap(&mut self) -> &Board {
    let tmp = self.cur;         // 1
    self.cur = self.next;       // 2
    self.next = tmp;            // 3
    self
}

如果我们逐行分析:

  1. self.cur现已未初始化
  2. self.next现已未初始化
  3. 一切都再次犹太洁食
  4. 如果出于某种原因,在第(3)行改变以收紧情况之前计算被中断,self现在已经中毒并且可能导致各种令人讨厌的事情发生。值得注意的是,它的析构函数可能会尝试两次释放内存,例如。

    理论上,您可以让编译器检查临时漏洞并毫无疑问地证明:

    • 在打孔时没有功能访问self
    • 在范围的最后,无论是正常到达还是通过展开,孔都会被填满

    确实在某种程度上它被认为是......但事实是它很复杂,而且有很多可用的解决办法。

      

    因此?

    答案在于std::mem,它公开了以安全的方式执行这种低级操作的函数。虽然函数本身是使用unsafe实现的,但它们依赖于对语言和运行时的理解来暴露安全接口。

    您感兴趣的两个特定功能是:

    • replace:将dest: &mut T的内容替换为src: T并返回之前dest
    • 背后的内容
    • swap:交换其参数的内容

    使用这两个简单且安全的原语,可以避免在数据中打孔。