英文:
Double loop over one collection in Rust where one loop changes it
问题
我试图迭代集合`ants`(`Vec<Ant>`)。我不能克隆对象。
```lang-rust
for ant1 in &mut self.ants {
for ant2 in &self.ants {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2); // fn meet(&mut self, other: &Self); // - 需要。
}
}
}
借用检查器出现问题。如何正确做?
一个解决方案是复制所需的字段吗?
<details>
<summary>英文:</summary>
I'm trying to iterate over the collection `ants` (`Vec<Ant>`). I can't clone the objects.
```lang-rust
for ant1 in &mut self.ants {
for ant2 in &self.ants {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2); // fn meet(&mut self, other: &Self); // - needs.
}
}
}
The borrow checker hits my hands. How to do that rightly?
Would a solution be to copy needed fields?
答案1
得分: 3
你可以使用 split_at_mut
来仅查看稍后的蚂蚁。
for outer in 1..self.ants.len() {
let (begin, end) = self.ants.split_at_mut(outer);
let ant1 = begin.last_mut().unwrap();
for ant2 in end {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2);
ant2.meet(ant1);
}
}
}
使用这种实现方式,一只蚂蚁无法与自己相遇,但无论如何,由于 meet
的签名,这是不可能的。这只有在一只蚂蚁可以与自身不相等时才重要,所以如果你有一个合理的 PartialEq
实现,这不会有关。
这个实现还改变了相遇的顺序。ant1
将在相同位置与 ant2
相遇,但与你的代码相比,ant2
会比 ant1
更早地与 ant1
相遇。它的优点是计算 distance
的次数减少了一半。
如果你想保持顺序,可以遍历之前和之后的蚂蚁。
for outer in 1..self.ants.len() {
let (begin, end) = self.ants.split_at_mut(outer);
let (ant1, begin) = begin.split_last_mut().unwrap();
for ant2 in begin.into_iter().chain(end) {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2);
}
}
}
再次强调,这不会比较一只蚂蚁与自己,但除此之外,与你的代码相同。
英文:
You can use split_at_mut
to only look at later ants.
for outer in 1..self.ants.len() {
let (begin, end) = self.ants.split_at_mut(outer);
let ant1 = begin.last_mut().unwrap();
for ant2 in end {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2);
ant2.meet(ant1);
}
}
}
With this implementation, an ant can't meet itself, but that is impossible anyway due to the signature of meet
. That is only important if an ant can be inequal to itself, so if you have a sensible PartialEq
implementation, this doesn't matter.
This implementation also changes the order of meets. ant1
will meet ant2
at the same point, but ant2
will meet ant1
earlier than in your code. It has the advantage of calculating distance
half as many times, though.
If you want to keep the order, you can loop over previous and later ants.
for outer in 1..self.ants.len() {
let (begin, end) = self.ants.split_at_mut(outer);
let (ant1, begin) = begin.split_last_mut().unwrap();
for ant2 in begin.into_iter().chain(end) {
if ant1 != ant2 && distance(ant1, ant2) <= Ant::visibility_range() {
ant1.meet(ant2);
}
}
}
Again, this doesn't compare an ant to itself, but everything else is the same as your code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论