某些算法递归地将数组分成更小的部分。您可以构建一个由此类进程产生的显式二叉树,其中每个叶子都包含一个不相交的数组切片。如果您需要更改或重新排序叶子中的元素,则其切片必须是可变的。
enum Tree<'a> {
Branch(Box<[Tree<'a>; 2]>),
Leaf(&'a mut[f32]),
}
假设我需要拆分大于某个阈值的所有叶子。容易:递归地从树上走下树;当我找到一片足够长的叶片时,将它分成两半,将它们包裹成一个2叶子树,然后更换叶子。
impl<'a> Tree<'a> {
fn split(&mut self, max: usize) {
match self {
&mut Tree::Branch(ref mut trees) => {
trees[0].split(max);
trees[1].split(max);
},
&mut Tree::Leaf(ref mut leaf) if leaf.len() > max => {
let mid = leaf.len() / 2;
let (l, r) = leaf.split_at_mut(mid);
let trees = [Tree::Leaf(l), Tree::Leaf(r)];
*self = Tree::Branch(Box::new(trees));
},
}
}
}
不幸的是,借用检查器无法为ref mut leaf
模式找到合适的生命周期。在允许分配到*self
之前,它希望它已经死了,但我不知道如何从匹配组中进行分配。
如何使这项工作?
答案 0 :(得分:3)
你可以使用两个技巧使它工作,这在代码中有解释。
use std::mem;
enum Tree<'a> {
Branch(Box<[Tree<'a>; 2]>),
Leaf(&'a mut[f32]),
Placeholder, // it's not very nice hack, but it's required for mem::replace
}
impl<'a> Tree<'a> {
fn split(&mut self, max: usize) {
let mut needs_split = false;
match self {
&mut Tree::Branch(ref mut trees) => {
trees[0].split(max);
trees[1].split(max);
},
&mut Tree::Leaf(ref mut leaf) if leaf.len() > max => {
// Postpone modification of *self. We can't do it now while
// a part of *self is borrowed
needs_split = true;
},
_ => {}
}
if needs_split {
// move *self into cself, to be able to
// deconstruct content, while keeping *self not borrowed
let cself = mem::replace(self, Tree::Placeholder);
if let Tree::Leaf(leaf) = cself {
let mid = leaf.len() / 2;
let (l, r) = leaf.split_at_mut(mid);
let trees = [Tree::Leaf(l), Tree::Leaf(r)];
*self = Tree::Branch(Box::new(trees));
} else {
unreachable!()
}
}
}
}
答案 1 :(得分:2)
我不确定如何修复整个案例,但我或许可以引导你朝着正确的方向前进。首先,您需要明确self
的生命周期:
fn split(&'a mut self, max: usize)
下一个问题是非详尽的比赛;这可以通过以下基本情况轻松避免(暂时):
_ => unimplemented!()
现在的问题是你在第一场比赛中两次可怜地借trees
次;这可以通过使用循环来解决:
&mut Tree::Branch(ref mut trees) => {
for tree in trees.iter_mut() {
tree.split(max);
}
}
现在你有:
error[E0506]: cannot assign to `*self` because it is borrowed
--> <anon>:18:17
|
14 | &mut Tree::Leaf(ref mut leaf) if leaf.len() > max => {
| ------------ borrow of `*self` occurs here
...
18 | *self = Tree::Branch(Box::new(trees));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `*self` occurs here
可以通过不对匹配臂中的Leaf
进行解构并使用辅助函数来避免这种情况:
impl<'a> Tree<'a> {
fn get_trees(&'a mut self, max: usize) -> Option<[Tree<'a>; 2]> {
if let &mut Tree::Leaf(ref mut leaf) = self {
if leaf.len() > max {
let mid = leaf.len() / 2;
let (l, r) = leaf.split_at_mut(mid);
Some([Tree::Leaf(l), Tree::Leaf(r)])
} else {
None
}
} else {
None
}
}
}
和
&mut Tree::Leaf(_) => {
let trees = self.get_trees(max).unwrap(); // safe (under a valid match arm)
*self = Tree::Branch(Box::new(trees));
}
现在出现了一个更大的问题,因为在借用它时你无法分配给self
。我会考虑使Clone
能够(并根据trees
的副本创建self
),但在您的情况下,它不能自动导出;也许别人会有更好的主意。