我在试图理解为什么我无法返回从
&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!(...)
时遇到了同样的问题,这是一个我似乎无法活得足够长的变量,对我来说没有用处。
首先,让我们看看实际预期的寿命是多少。
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
。不幸的是,您不能在这里自由选择返回类型。
要返回比方法调用寿命更长的字符串切片,我看到两个选项:
使用
&'static
字符串切片。这肯定会比调用更长久,但它要求字符串在编译时已知,否则会泄漏内存。字符串文字的类型为 &'static str
。如果描述不包含任何动态数据,这是一个合适的选项。
将拥有的字符串存储在
LexicalError
本身中。这确保您可以返回一个在 self
的整个生命周期内有效的指针。您可以在 desc: String
中添加一个字段 LexicalError
并在构造错误时进行格式化。那么该方法将被实现为
fn description(&self) -> &str {
&self.desc
}
为了重复使用,您可以让
Display
写入相同的字符串。
根据Error
Display
可用于提供更多详细信息。如果您希望在错误中包含动态数据,那么 Display
是对其进行格式化的好地方,但您可以在 description
中省略它。这将允许使用第一种方法。
你可以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));
}
}