The idea is that the Foo keeps a mutable reference, and when calling consume_i, it do not own any reference. But the code does not work:
let mut i = 0;
let mut foo = Foo {
i: None
};
foo.add_i(&mut i);
foo.consume_i();
foo.add_i(&mut i);
foo.consume_i();
The code will report cannot borrow i as mutable more than once at a time error. And it is the same problem of "lifetime checker do not aware of clear() of a vector". But the solution in the link does not fit very well in my code.
Is there any way to change the API of Foo as minimum as possible, to let the user write codes like above?
P.S. in the real case, create of Foo is very expansive and a solution of "drop and re-create Foo" is not acceptable.
Now, note, the above has identical signatures for add_i / consume_i as your function above.
A compiler that operates on only the type signature of functions (and not their content) would not be able to distinguish your impl from my impl, and since my impl can't compile, it's unlikely yours will.
You should avoid having references in structs as much as possible. In this case you could divide it into a normal struct owns its data, and a temporary view that refers to the data stored elsewhere:
struct Foo { /* no references here */ }
struct FooWithData<'a, 'f> { data: &'a mut i32, foo: &'f mut Foo }
let foo = Foo;
let foo_loaded = foo.with(&mut i);
foo_loaded.consume();
let foo_loaded = foo.with(&mut i);
foo_loaded.consume();
The hard part here is that you can't have Foo and FooWithData stored in a struct together, since that would be self-referential.
This is suspicious. What it's saying is that your i variable's lifetime is exactly equal to the &'a mut stored in Foo. Unlike immutable references, mutable references are "invariant" so the compiler doesn't have the wiggle room to shorten/lengthen lifetimes so they match.
Instead of recreating Foo from scratch, what about using update syntax to create a new Foo with a nicer lifetime like this?