Yes, I was thinking about it some more yesterday, and I came up with a counter-example as well: Rust Playground
Thank you for the thorough explanation, it made things clearer. The problem is that you cannot "copy" the inner mutable reference from behind an outer (mutable) reference, you can only re-borrow it as an outer reference.
Also, if I understand correctly, the inner lifetime is a superlifetime of the outer lifetime in this case.
So, what to do?
Fist, let's explain what I was trying to do in the first place. I was trying to make a variant of retain, that would give you ownership of the items that you are filtering out. This is what I came up with:
pub enum Retain<F> {
Keep,
Take(F),
}
trait RetainWith<T> {
fn retain_with<F: FnOnce(T)>(&mut self, f: impl FnMut(&T) -> Retain<F>);
}
Instead of returning a boolean (keep/discard), you return an enum and if you want to remove the item, you take it by the means of the function what will receive the item. Rust Playground
First I used lambdas, and that didn't work, so then I tried implementing them manually, and that still didn't work (that's when I discovered this issue), so I just gave up and put the value behind Rc<RefCell>
and now it works, but it kind of sucks.
Needless to say, you would be better of using drain filter for this, but still, I wanted to see if it could be done.
Any solutions?
@kornel 's solution doesn't really work for me, because as I said, I want the implementators to be able to return a computed value. Moreover, some implementations need to return a computed value that contains the (inner) reference in it's data!
As you explained, this is possible when not using the trait, with an annotation like this:
fn gimme_mut<'outer>(&'outer mut self) -> &'outer mut i32
or even
fn gimme_mut<'outer>(&'outer mut self) -> SomeStruct<&'outer mut i32>
for a computed value that contains the inner reference.
To be cleared, I want to return the inner reference, but with the outer lifetime, which is possible in both of these 2 examples above.
But it is not possible when the return type is generic and it's not aware that one of the implementators might want to return SomeStruct
for example. That is currently impossible in Rust if I understand correctly.
But does it have to be? What about a syntax like this:
fn gimme_mut<'a>(&'a mut self) -> T + 'a;
It would tell the compiler that the returned value might contain a reference to self and therefore the object must not be used until the returned value is dropped. It would work the same as &mut T
in that way, except it would not force the return type to be &mut T
; it could be anything that contains &mut T
, or something that has no reference at all!
There probably are more practical / idiomatic solutions to problems where this would be useful, but still, it's important to think about these problems and how they could be solved.