为什么我不能 return 从字符串生成的 &str 值?

Why can't I return an &str value generated from a String?

我无法理解为什么我不能 return 从 String 生成的 &str 值(天哪,as_str 什么时候准备好了吗?)我做错了什么。我之所以有这个想法,是因为我所做的任何事情都无法使价值足够长的时间来使用。

我正在尝试为自定义结构实施 error::Error

impl error::Error for LexicalError {
    fn description(&self) -> &str {
        let s = format!("{}", self);

        // s doesn't live long enough to do this, I've tried 
        // cloning s and using that, but still the clone doesn't
        // live long enough.
        s.trim()
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

(对于完整的片段,这里是 playpen

我不知道如何从 description 中 return &str,我想重用 Display 逻辑,除非我完全误解了什么description 应该是 returning(也许是问题的简短描述)。或者,我遇到了与 format!(...) 的 return 相同的问题,这是一个我似乎无法活到对我有用的变量。

首先,让我们看看实际预期的寿命是多少。 description:

的签名中有一个隐含的生命周期
fn description(&self) -> &str
// Can be rewritten as
fn description<'a>(&'a self) -> &'a str

returned 指针必须至少在 self 期间有效。现在考虑 s。它将持有一个 String,一个拥有的字符串,并且它在函数结束时超出范围。到return&s就无效了,因为return函数的时候s就没了。 trim return 是借用 s 的字符串切片,但该切片再次仅在 s 有效期间有效。

您需要 return 一个比方法调用还长的字符串切片,因此这排除了堆栈上的任何内容。如果您可以自由选择 return 类型,解决方案是将字符串移出函数。为此,需要一个拥有的字符串,然后 return 类型将是 String,而不是 &str。遗憾的是,您无法在此处自由选择 return 类型。

要return一个比方法调用还长的字符串切片,我看到两个选项:

  1. 使用 &'static 字符串切片。这肯定会超过调用,但它需要在编译时知道该字符串。字符串文字的类型为 &'static str。如果描述不包含任何动态数据,这是一个合适的选项。

  2. 将拥有的字符串存储在 LexicalError 本身中。这确保您可以 return 一个指向它的指针,该指针在 self 的整个生命周期内都有效。可以在LexicalError中增加一个字段desc: String,在构造错误的时候进行格式化。然后该方法将实现为

    fn description(&self) -> &str {
        &self.desc
    }
    

    为了重复使用,可以让Display写入相同的字符串。

根据 documentation of ErrorDisplay 可用于提供更多详细信息。如果您希望在错误中包含动态数据,那么 Display 是格式化它的好地方,但您可以省略 description。这将允许使用第一种方法。