Option::as_ref
Let’s consider the following function:
use std::ptr::NonNull;
fn transform<T>(option: &Option<NonNull<T>>) -> Option<&T> {
option.map(|x| unsafe { x.as_ref() })
}
The function transform
takes an Option<NonNull<T>>
as input, and converts the inner pointer to an immutable reference &T
if possible. The method NonNull::as_ref()
is marked unsafe so we need an unsafe
block. The snippet causes an compilation error:
error[E0515]: cannot return value referencing function parameter `x`
--> src/main.rs:6:29
|
6 | option.map(|x| unsafe { x.as_ref() })
| -^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `x` is borrowed here
This is a common mistake when transforming Option
s. To figure out the problem, we may try to take apart the signature and see how the value flows:
fn Option::map<T, F>(self, f: F) -> Option<&T>
where F: FnOnce(NonNull<T>) -> Option<&T>
{}
// which implies:
fn __closure<T>(x: NonNull<T>) -> &T {}
unsafe fn NonNull::as_ref<T, 'a>(&'a self) -> &'a T {}
where __closure
denotes the closure Option::map
takes.
Note that Option::map
is a self-consuming method. During the calling, option
is destructed, and the internal value with type NonNull<T>
flows into __closure
. The closure, however, consumes its argument as well. Consequently x
would have a lifetime trapped in the closure. This is what “data owned by the current function” in the error message means.
Now take a look into the closure. Inside we call NonNull::as_ref()
to convert a pointer into a reference, which assumes the pointer should live as long as the reference returned. However, the implication could not be satisfied, since x
the pointer lives only within the closure, but the reference would be passed out of the closure. The compiler complains for the lifetime mismatch.
One can always employ Option::as_ref()
as a solution. The function has a signature as below:
fn Option::as_ref<T>(&self) -> Option<&T> {}
Calling .as_ref()
on an Option<T>
instance, say x
, will return another Option with type Option<&T>
, say ref_x
, which holds the reference to the inner value of x
. It’s worth noting that .as_ref()
takes x
by reference, so no consuming happens here. Now we can perform .map()
or .unwrap()
on ref_x
to extract the internal &T
, and call non-consuming methods on it (e.g., NonNull::as_ref
). ref_x
will still be dropped after that, but it does not matter, since all it have is a reference.
We can correct our code like this:
fn transform<T>(option: &Option<NonNull<T>>) -> Option<&T> {
option
.as_ref() // Note here
.map(|x| unsafe { x.as_ref() })
}
Author: hsfzxjy.
Link: .
License: CC BY-NC-ND 4.0.
All rights reserved by the author.
Commercial use of this post in any form is NOT permitted.
Non-commercial use of this post should be attributed with this block of text.
OOPS!
A comment box should be right here...But it was gone due to network issues :-(If you want to leave comments, make sure you have access to disqus.com.