【问题标题】:Why I can't return fmt::Arguments<'a> from &'a T?为什么我不能从 &'a T 返回 fmt::Arguments<'a>?
【发布时间】:2016-12-21 13:40:43
【问题描述】:

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

这有效,即使有省略:

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

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

但这不是:

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) })...

这是一个错误吗?还是我误解了生命周期?

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

【问题讨论】:

  • 您的前两个示例返回一个引用,因此它们与最后一个返回拥有对象的示例没有真正可比性。
  • 有谁知道现在是否有任何解决方案或替代方案?

标签: rust lifetime


【解决方案1】:

要了解发生了什么,让我们看看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)],
        },
    )
}

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

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> {
   |                                                                         ^

具体来说,在堆栈上创建了一个ArgumentV1,并对其进行了引用。您不能从函数中返回该引用。

第二个错误:

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> {
   |                                                                         ^

注意format! family of macros doesn't take their arguments by value;他们会自动插入参考。你不希望println! 拥有你的价值!

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

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

这是对的。您可以只返回返回该输入参数的一部分。您不能创建一个全新的值并在该生命周期内返回它。

【讨论】:

  • 哦.. 生成的代码显示发生了什么.. 谢谢。我只是决定改用 FormatArg。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多