Reputation: 127771
I have something like the following methods on a structure:
impl<'a> SomeStructure<'a> {
// I need &'a mut because the iterator may mutate SomeStructure
fn iter<'a>(&'a mut self) -> SomeIterator<'a> {
SomeIterator { object: self }
}
fn test_something(&self) -> bool {
self.some_field < 0
}
}
And then I want to use them like that:
impl<'a> SomeTrait for &'a mut SomeStructure<'a> {
fn do_something(self) {
for e in self.iter() {
...
if self.test_something() {
break;
}
}
}
}
However, Rust does not allow it (I've fixed error messages so they refer to the sample code above):
io/convert_io.rs:119:17: 119:22 error: cannot borrow `*self` as immutable because it is also borrowed as mutable
io/convert_io.rs:119 if self.test_something() {
^~~~~
io/convert_io.rs:117:18: 117:23 note: previous borrow of `*self` occurs here
io/convert_io.rs:117 for e in self.iter() {
^~~~~
But I do not see how immutable borrowing inside self.test_something()
call can interfere with creating an iterator earlier, even if the iterator does mutate original object.
Could you please explain what's going on here and how to fix it?
Upvotes: 3
Views: 214
Reputation: 102066
This is possibly bug #8372 caused by the minimum-that-works implementation of the current for
. It is implemented as a macro such that
for pattern in iterator { body }
expands to (you can see this by running rustc --pretty expanded foo.rs
)
{
let it = &mut iterator;
loop {
match it.next() {
None => break,
Some(pattern) => { body }
}
}
}
The problem is the &mut iterator
borrow, which stops iterator
being used directly while it
is in scope. You can normally work around this by manually writing the expansion yourself:
impl<'a> SomeTrait for &'a mut SomeStructure<'a> {
fn do_something(self) {
let mut it = self.iter();
loop {
match it.next() {
None => break
Some(e) => {
if self.test_something() {
break;
}
}
}
}
}
}
That said... this may not actually work in this case if self.iter()
borrows self
(especially if test_something
takes &mut self
, since the compiler has to disallow mutation or the iterator could be invalidated).
If you were to add a .view_creator()
method to the return of self.iter()
(assuming you have a reference to self
in the self.iter()
type) then it.view_creator().test_something()
would work (with the manually unwrapped for loop).
(FWIW, it's a little peculiar to have a trait taking self
and implementing it on &mut Thing
rather than taking &mut self
and implementing it straight on Thing
; although there are good reasons for it sometimes.)
Upvotes: 2