如何交换结构的两个字段

par*_*tic 5 swap struct reference rust

我开始研究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],
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.我也能够改变两种载体.但后来我希望能够交换两个向量(或者更确切地说是它们的引用),例如:

fn swap(&mut self) -> &Board {
    let tmp = self.cur;
    self.cur = self.next;
    self.next = tmp;
    self
}
Run Code Online (Sandbox Code Playgroud)

它失败了cannot move out of borrowed content [E0507],我想我能理解.我也尝试了mem::swap在类似的标题问题中找到的但没有成功.

我怎样才能使这个例子有效?(因为我是Rust的初学者,所以请不要犹豫,建议不同的数据表示).

Mat*_* M. 5

有什么问题?

您正在对数据打孔

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

如果我们逐行分析:

  1. self.cur 现在尚未初始化
  2. self.next 现在尚未初始化
  3. 一切又洁净了

如果出于某种原因,在第(3)行进行更改以加强这种情况之前中断了计算,self则该操作现在中毒了,并可能导致各种令人讨厌的事情发生。值得注意的是,它的析构函数可能会尝试两次释放内存。

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

  • self打孔时无法使用任何功能
  • 到示波器结束时,无论是正常到达还是通过展开,都可以再次填充孔

确实在某个时候已经考虑过了……但是事实是它很复杂,并且随时都有解决方法。

所以?

答案在于std::mem公开功能以安全的方式执行此类低级操作。虽然功能本身是unsafe在幕后使用的,但它们依靠对语言和运行时的理解来公开安全的接口。

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

  • replace:替换dest: &mut Tby 的内容src: T并返回之前包含的内容dest
  • swap:交换其参数的内容

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


Luk*_*odt 4

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

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

这有效。请注意,使用时.您正在解除引用self。所以既有self&mut Boardself.cur就有型Vec<u32>。因此,编译器抱怨“移出借用的内容”,我们需要额外的&muts。