Temporary Value Dropped While Borrowed
I am at a point in my Rust development where I have started to identify some… slightly sub-optimal approaches I may have taken in my naïveté. It occurred to me that other people at a similar stage of their Rust journey might benefit from seeing my n00b mistakes and how I fixed them once I had a little bit more insight.
Today’s exercise is this function:
This uses the git2 crate to create a child branch off an existing branch. It takes that parent branch, gets a git reference from it (a type of object in the git internals taxonomy, not a Rust reference), converts it to a Commit object, gets a (Rust) reference to it (because the
git2::Repository::branch function takes a
&Commit), and then handles the potential error case. All nice and fluent, and straightforward to understand (especially with CLion showing you all the types).
Just one small problem: this won’t compile.
Because we’re taking a reference to a temporary, when the temporary goes out of scope at the end of my function call chain, the reference is no longer valid, so rustc plays the “Nope!” card.
Following the instruction provided by the compiler (“consider using a ‘let’ binding to create a longer lived value”), I reluctantly restructure the code like so:
Ugh. That is hideous, but it compiles, so ¯\_(ツ)_/¯.
Days and weeks pass. This abomination haunts my dreams.
Note the bit about Polonius. Guided by this comment on the Rust forums, I recently tried compiling it using Polonius, which… did not work. Which I should have known. Polonius won’t fix the fact that I grabbed a reference to a dangling temporary.
So I put on my thinking cap. Aha, says I, it is a
&Commit, which is why it has a limited lifetime. If I call
to_owned(), that should give me a fully-owned
Commit instance that will last until the function returns.
That fixed my original problem, but since I now have a
Commit, I have to pass it as
&branch_ref to make the subsequent call work.
Wait a second.
I’m doing something super dumb here. I’m converting a
Branch into an owned
Commit, taking a reference to it, and then re-owning it. What happens if I just remove
As it turns out, I was trying too hard. All I needed to do was convert the owned
Branch to an owned
Commit and then pass a reference to that in my function call. Note that I also changed the variable name to better reflect its new purpose.
If you’re wrestling with learning Rust, I hope you find this helpful. If you have some Rust code that you feel is suboptimal but you just can’t see how to make it better, hit me up on Twitter at @mrtact.