如何交换结构体中的两个字段

6

我已经开始学习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个回答

6

问题是什么?

您的数据中存在漏洞

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. 一切又恢复正常了
如果由于某种原因,在第三行改变之前计算被中断,那么`self`现在就被破坏了,可能会导致各种不良后果。特别是,它的解构函数可能会尝试两次释放内存。
理论上,您可以让编译器检查临时洞并无疑地证明:
- 没有函数在插入洞时访问`self` - 在作用域结束时,无论是通过正常到达还是通过展开,洞都被填充起来了
事实上,在某些情况下,这个想法被认为是可行的,但事实上它很复杂,并且有现成的解决方法。
那么答案就在于`std::mem`,它公开了以安全方式执行此类低级操作的功能。虽然这些函数本身在幕后使用`unsafe`实现,但它们依赖于对语言和运行时的理解来公开安全接口。
您将感兴趣的两个特定函数是:
- `replace`:将`dest: &mut T`的内容替换为`src: T`,并返回以前包含在`dest`后面的内容 - `swap`:交换其参数的内容
有了这两个简单而安全的基元,您可以避免在数据中插入洞。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接