In order to relate this information to the quoted examples from other threads:
expr.clone().gettype()
Here, I assume gettype()
is a &self
method of some type Foo
while expr.clone(): Foo
is an owned value. Hence the method call desugars to something like Foo::gettype(&expr.clone())
, which is the same case as above: Evaluating &expr.clone()
needs to put the value created by evaluating expr.clone()
, so a temporary is created to hold that value.
Furthermore, I assume that gettype
has some kind of function signature fn gettype(&self) -> &Bar
or fn gettype(&self) -> Baz<'_>
, i.e. the returned value still contains that reference to the temporary (or to a part of the temporary), and the type signature tracks the requirement on lifetimes that this entails. (In case you’re unfamiliar with how to read those function signatures w.r.t. lifetimes, check out this page of the Nomicon on lifetime elision).
So after the statement arraytype = Some(expr.clone().gettype());
is evaluated, the temporary containing the expr.clone()
value is dropped, and hence arraytype
contains a value that can’t be used anymore. Since it is used, the compiler complains.
error[E0716]: temporary value dropped while borrowed
--> src/version/interpreter.rs:160:38
|
160 | arraytype = Some(expr.clone().gettype());
| ^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
...
167 | match arraytype {
| --------- borrow later used here
In the other case, there’s less guesswork needed for the function signatures involved. We’d like to understand why in
let n1 = p.clone().unwrap().borrow();
there’s a temporary being created containing p.clone().unwrap()
. This expression does evaluate to a value of type Rc<RefCell<TreeNode>>
, and the method RefCell::borrow
expects &self
, i.e. a &RefCell<TreeNode>
. There’s also the intermediate Rc<…>
to get rid of. Method resolution thus (essentially) desugars to
let n1 = RefCell::borrow(Rc::deref(&p.clone().unwrap()));
meaning that there is a step of creating a reference to p.clone().unwrap()
. Or if you want to desugar all the method calls for good measure (and for comparison), it becomes
let n1 = RefCell::borrow(Rc::deref(&Option::unwrap(Clone::clone(p))));
Again, looking at &p.clone().unwrap()
(or &Option::unwrap(Clone::clone(p))
), as we have an &…
expression, and its right-hand-side is a value, not a place, so a temporary is created that the reference can refer to.
The borrow
method does not only take &self
but also returns a Ref<'_, …>
type that has a lifetime connected to the lifetime of &self
(due to the fact that it also still contains a reference to the RefCell
). And the dereferencing step, Rc::deref
is a (&Rc<RefCell<TreeNode>>) -> &RefCell<TreeNode>
method, the lifetimes of the input and ouput are also connected.
As another point of comparison, the approach in the solution,
let n1 = p.as_ref().unwrap().borrow();
desugars to
let n1 = RefCell::borrow(Rc::deref(Option::unwrap(Option::as_ref(p))));
The types here work out so that no value needs to be borrowed (or more generally used in any place-expression-context), so no temporary needs to be created. In fact, most intermediate values already are references which are borrowing some other preexisting place. The types of the intermediate results are
p: &Option<Rc<RefCell<TreeNode>>>,
Option::as_ref(p): Option<&Rc<RefCell<TreeNode>>>,
Option::unwrap(Option::as_ref(p)): &Rc<RefCell<TreeNode>>,
Rc::deref(Option::unwrap(Option::as_ref(p))): &RefCell<TreeNode>,
RefCell::borrow(Rc::deref(
Option::unwrap(Option::as_ref(p))
)): std::cell::Ref<'_, TreeNode>,