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

问题描述 投票:0回答:2

我在试图理解为什么我无法返回从

&str
生成的
String
值时遇到了一些麻烦(天哪,
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
返回 &str,我想重用
Display
逻辑,除非我完全误解
description
应该返回什么(也许是简短的描述)问题)。或者,我在返回
format!(...)
时遇到了同样的问题,这是一个我似乎无法活得足够长的变量,对我来说没有用处。

rust lifetime
2个回答
23
投票

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

description
的签名中有一个隐含的生命周期:

fn description(&self) -> &str
// Can be rewritten as
fn description<'a>(&'a self) -> &'a str

返回的指针必须至少在

self
内有效。现在考虑
s
。它将保存一个
String
,一个拥有的字符串,并且它在函数末尾超出范围。返回
&s
是无效的,因为函数返回时
s
就消失了。
trim
返回借用
s
的字符串切片,但该切片同样仅在
s
有效期间有效。

您需要返回一个比方法调用寿命更长的字符串切片,因此这排除了堆栈上的任何内容。如果您可以自由选择返回类型,解决方案是将字符串移出函数。为此,需要一个拥有的字符串,然后返回类型将是

String
,而不是
&str
。不幸的是,您不能在这里自由选择返回类型。

要返回比方法调用寿命更长的字符串切片,我看到两个选项:

  1. 使用

    &'static
    字符串切片。这肯定会比调用更长久,但它要求字符串在编译时已知,否则会泄漏内存。字符串文字的类型为
    &'static str
    。如果描述不包含任何动态数据,这是一个合适的选项。

  2. 将拥有的字符串存储在

    LexicalError
    本身中。这确保您可以返回一个在
    self
    的整个生命周期内有效的指针。您可以在
    desc: String
    中添加一个字段
    LexicalError
    并在构造错误时进行格式化。那么该方法将被实现为

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

    为了重复使用,您可以让

    Display
    写入相同的字符串。

根据Error

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


0
投票

你可以Box::leak()从String中获取静态str,使用后手动删除它。

fn main() {
    let s1 = format!("abc");

    // s is static lifetime, can match the lifetime of &str
    let s = Box::leak(s1.into_boxed_str()); 

    // drop it manually.
    unsafe {
        mem::drop(Box::from_raw(s as *const str as *mut str));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.