为什么我无法从 &'a T 返回 fmt::Arguments<'a> ?

kdy*_*kdy 6 lifetime rust

根据我对生命周期的理解,如果函数的调用者在参数上指定生命周期,我可以返回具有该生命周期的类型。

即使有省略,这也是有效的:

pub fn substr(s: &str) -> &str {
    &s[0..1]
}

pub fn substr_ex<'a>(s: &'a str) -> &'a str {
    &s[0..1]
}
Run Code Online (Sandbox Code Playgroud)

但这并没有:

use std::fmt::Arguments;

pub fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> {
    format_args!("{:?}", t)
}
Run Code Online (Sandbox Code Playgroud)
pub fn substr(s: &str) -> &str {
    &s[0..1]
}

pub fn substr_ex<'a>(s: &'a str) -> &'a str {
    &s[0..1]
}
Run Code Online (Sandbox Code Playgroud)

这是一个错误吗?还是我对生命的理解有误?

婴儿围栏:https://play.rust-lang.org/ ?gist=5a7cb4c917b38e012f20c771893f8b3b&version=nightly

She*_*ter 5

为了了解发生了什么,让我们看一下宏扩展版本

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)],
        },
    )
}
Run Code Online (Sandbox Code Playgroud)

这有助于解释第一个错误:

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)],
        },
    )
}
Run Code Online (Sandbox Code Playgroud)

具体来说,一个ArgumentV1正在堆栈上创建 an 并对其进行引用。您无法从函数返回该引用。

第二个错误:

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> {
   |                                                                         ^
Run Code Online (Sandbox Code Playgroud)

请注意,format!宏系列按值获取参数;他们会自动插入参考文献。你不会想要println!拥有你的价值!

这意味着打印的值实际上是&&'a T-对堆栈分配值的引用t!同样,您不能返回对堆栈上分配的内容的引用。

如果函数的调用者指定参数的生命周期,我可以返回具有该生命周期的类型。

这话只对了一半。您只能返回该输入参数的一部分。您无法创建一个全新的值并在该生命周期内返回它。