Based on my understanding of lifetimes, if the caller of a function specifies a lifetime on a parameter, I can return a type with that lifetime.
This works, even with elision:
pub fn substr(s: &str) -> &str {
&s[0..1]
}
pub fn substr_ex<'a>(s: &'a str) -> &'a str {
&s[0..1]
}
But this doesn't:
use std::fmt::Arguments;
pub fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> {
format_args!("{:?}", t)
}
error: borrowed value does not live long enough
--> <anon>:16:18
|
16 | format_args!("{:?}", t)
| ^^^^^^ does not live long enough
17 | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the lifetime 'a as defined on unknown free region bounded by scope CodeExtent(38/CallSiteScope { fn_id: NodeId(42), body_id: NodeId(92) })...
error: `t` does not live long enough
--> <anon>:16:26
|
16 | format_args!("{:?}", t)
| ^ does not live long enough
17 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the lifetime 'a as defined on unknown free region bounded by scope CodeExtent(38/CallSiteScope { fn_id: NodeId(42), body_id: NodeId(92) })...
Is this a bug? Or am I misunderstanding lifetimes?
Playpen: https://play.rust-lang.org/?gist=5a7cb4c917b38e012f20c771893f8b3b&version=nightly
To understand what's happening, let's look at the macro-expanded version:
fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> {
::std::fmt::Arguments::new_v1(
{
static __STATIC_FMTSTR: &'static [&'static str] = &[""];
__STATIC_FMTSTR
},
&match (&t,) {
(__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)],
},
)
}
This helps explain the first error:
error: borrowed value does not live long enough
--> src/main.rs:9:36
|
9 | &match (&t,) {
| ^ temporary value created here
...
15 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the block at 4:72...
--> src/main.rs:4:73
|
4 | fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> {
| ^
Specifically, an ArgumentV1
is being created on the stack and a reference is being taken of it. You cannot return that reference from the function.
The second error:
error: `t` does not live long enough
--> src/main.rs:9:44
|
9 | &match (&t,) {
| ^ does not live long enough
...
15 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the block at 4:72...
--> src/main.rs:4:73
|
4 | fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> {
| ^
Note that the format!
family of macros doesn't take their arguments by value; they automatically insert a reference. You wouldn't want println!
to take ownership of your value!.
This means that the printed value is actually a &&'a T
- a reference to the stack-allocated t
value! Again, you cannot return a reference to something allocated on the stack.
if the caller of a function specifies a lifetime on a parameter, I can return a type with that lifetime.
This is halfway true. You can return only return a piece of that input parameter. You cannot create a completely new value and return it with that lifetime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With