函数返回值的生命周期错误
Lifetime error for returned value of a function
这是我尝试实现的一段代码的简化版本:
struct FirstStruct
{
a: i8,
}
impl FirstStruct
{
fn get(&self) -> Option<&str>
{
Some("aaa")
}
}
pub struct SecondStruct<'a>
{
pub name: Option<&'a str>,
}
impl<'a> SecondStruct<'a>
{
fn extract_string(obj: &/*'a*/ FirstStruct) -> Option<&'a str>
{
obj.get() //this is where the error happen
}
pub fn from_string() -> SecondStruct<'a>
{
let obj = FirstStruct{a: 1};
SecondStruct{
name: SecondStruct::extract_string(&obj),
}
}
}
fn main()
{
let g_def_res = SecondStruct::from_string();
}
此代码抛出以下错误:
test2.rs:23:13: 23:18 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
test2.rs:23 obj.get() //this is where the error happen
^~~~~
test2.rs:21:5: 24:6 help: consider using an explicit lifetime parameter as shown: fn extract_string(obj: &'a FirstStruct) -> Option<&'a str>
test2.rs:21 fn extract_string(obj: &FirstStruct) -> Option<&'a str>
test2.rs:22 {
test2.rs:23 obj.get() //this is where the error happen
test2.rs:24 }
error: aborting due to previous error
应用建议的解决方案抛出此错误:
test2.rs:30:55: 30:58 error: `obj` does not live long enough
test2.rs:30 name: SecondStruct::extract_string(&obj),
^~~
test2.rs:27:5: 32:6 note: reference must be valid for the lifetime 'a as defined on the block at 27:4...
test2.rs:27 {
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
test2.rs:28:37: 32:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 28:36
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
error: aborting due to previous error
总结一下:
如何说 FirstStruct::get
的 return 值必须具有 SecondStruct::from_str
的 return 值之一的生命周期 |结构生命周期 'a
]?我认为两者指的是同一件事?
pub fn from_string() -> SecondStruct<'a> {
let obj = FirstStruct { a: 1 };
SecondStruct {
name: SecondStruct::extract_string(&obj),
}
}
此代码表示 "I will return a SecondStruct
with the lifetime 'a
"。代码的 caller 确定生命周期 'a
的长度。这几乎不是你想要的!
// Lifetime elision means the method is equivalent to this
// fn get<'a>(&'a self) -> Option<&'a str>
fn get(&self) -> Option<&str> {
Some("aaa")
}
此代码使用表示字符串 returned 将与 self
一样长。
把这两个概念放在一起,就可以理解你的错误了。变量 obj
仅定义为在函数调用处于活动状态时有效。但是,您正在尝试 return 对调用之外的结构内部工作的引用!实际上,您正在尝试 return 它 调用者决定的任意生命周期 !这是 Rust 防止你搬起石头砸自己的脚,为 Rust 万岁!
那么你是如何解决你的问题的?对于提供的示例代码,最简单的方法是只使用 'static
生命周期:
struct FirstStruct { a: i8 }
impl FirstStruct {
fn get(&self) -> Option<&'static str> { Some("aaa") }
}
pub struct SecondStruct<'a> { name: Option<&'a str> }
impl<'a> SecondStruct<'a> {
fn extract_string(obj: &FirstStruct) -> Option<&'static str> { obj.get() }
pub fn from_string() -> SecondStruct<'static> {
let obj = FirstStruct { a: 1 };
SecondStruct { name: SecondStruct::extract_string(&obj) }
}
}
fn main() {
let g_def_res = SecondStruct::from_string();
}
但这可能不是您真正想要的。接下来要尝试的是 embed FirstStruct
inside SecondStruct
,然后简单地委托给它。另一种选择是从 &str
移动到 String
- String
拥有字符串数据,因此您可以将所有权从 First
转移到 Second
.
无论您做什么,都必须确保字符串数据的来源比对 from_string
.
的函数调用更有效
Either the return value of FirstStruct::get
has been allocated on the stack or it has been allocated on the heap.
比这更棘手。 return 值在堆栈上总是 。也就是说,Option<&str>
在堆栈上占据了 space。 &str
可能包含指向在堆栈或堆上分配的内容的指针,此代码不知道。您所知道的是,指向的值保证在该特定 FirstStruct
项目的生命周期内有效。
您不拥有字符串,因此无法转让所有权。
I can't move FirstStruct because it is from another library (rustc-serialize
我不确定你的意思。如果你有一个对象,那么你可以将它嵌入到你的对象中。它来自另一个板条箱的事实并没有发挥作用。如果你有对某物的引用,那么你仍然可以捕获引用,但是你的对象必须比引用存在更短的时间(这样它就永远不会失效)。
Unwrapping Option, updating to a string and rewrapping in Option is a lot of boilerplate.
你见过Option::map
吗?它使这种事情变得非常简洁。结合From
,可以写一个很短的东西把一个Option<&str>
转换成Option<String>
:
// fn is just to establish some types, you'd just use the `.map` call in real code
fn foo(a: Option<&str>) -> Option<String> {
a.map(From::from)
}
这是我尝试实现的一段代码的简化版本:
struct FirstStruct
{
a: i8,
}
impl FirstStruct
{
fn get(&self) -> Option<&str>
{
Some("aaa")
}
}
pub struct SecondStruct<'a>
{
pub name: Option<&'a str>,
}
impl<'a> SecondStruct<'a>
{
fn extract_string(obj: &/*'a*/ FirstStruct) -> Option<&'a str>
{
obj.get() //this is where the error happen
}
pub fn from_string() -> SecondStruct<'a>
{
let obj = FirstStruct{a: 1};
SecondStruct{
name: SecondStruct::extract_string(&obj),
}
}
}
fn main()
{
let g_def_res = SecondStruct::from_string();
}
此代码抛出以下错误:
test2.rs:23:13: 23:18 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
test2.rs:23 obj.get() //this is where the error happen
^~~~~
test2.rs:21:5: 24:6 help: consider using an explicit lifetime parameter as shown: fn extract_string(obj: &'a FirstStruct) -> Option<&'a str>
test2.rs:21 fn extract_string(obj: &FirstStruct) -> Option<&'a str>
test2.rs:22 {
test2.rs:23 obj.get() //this is where the error happen
test2.rs:24 }
error: aborting due to previous error
应用建议的解决方案抛出此错误:
test2.rs:30:55: 30:58 error: `obj` does not live long enough
test2.rs:30 name: SecondStruct::extract_string(&obj),
^~~
test2.rs:27:5: 32:6 note: reference must be valid for the lifetime 'a as defined on the block at 27:4...
test2.rs:27 {
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
test2.rs:28:37: 32:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 28:36
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
error: aborting due to previous error
总结一下:
如何说 FirstStruct::get
的 return 值必须具有 SecondStruct::from_str
的 return 值之一的生命周期 |结构生命周期 'a
]?我认为两者指的是同一件事?
pub fn from_string() -> SecondStruct<'a> {
let obj = FirstStruct { a: 1 };
SecondStruct {
name: SecondStruct::extract_string(&obj),
}
}
此代码表示 "I will return a SecondStruct
with the lifetime 'a
"。代码的 caller 确定生命周期 'a
的长度。这几乎不是你想要的!
// Lifetime elision means the method is equivalent to this
// fn get<'a>(&'a self) -> Option<&'a str>
fn get(&self) -> Option<&str> {
Some("aaa")
}
此代码使用表示字符串 returned 将与 self
一样长。
把这两个概念放在一起,就可以理解你的错误了。变量 obj
仅定义为在函数调用处于活动状态时有效。但是,您正在尝试 return 对调用之外的结构内部工作的引用!实际上,您正在尝试 return 它 调用者决定的任意生命周期 !这是 Rust 防止你搬起石头砸自己的脚,为 Rust 万岁!
那么你是如何解决你的问题的?对于提供的示例代码,最简单的方法是只使用 'static
生命周期:
struct FirstStruct { a: i8 }
impl FirstStruct {
fn get(&self) -> Option<&'static str> { Some("aaa") }
}
pub struct SecondStruct<'a> { name: Option<&'a str> }
impl<'a> SecondStruct<'a> {
fn extract_string(obj: &FirstStruct) -> Option<&'static str> { obj.get() }
pub fn from_string() -> SecondStruct<'static> {
let obj = FirstStruct { a: 1 };
SecondStruct { name: SecondStruct::extract_string(&obj) }
}
}
fn main() {
let g_def_res = SecondStruct::from_string();
}
但这可能不是您真正想要的。接下来要尝试的是 embed FirstStruct
inside SecondStruct
,然后简单地委托给它。另一种选择是从 &str
移动到 String
- String
拥有字符串数据,因此您可以将所有权从 First
转移到 Second
.
无论您做什么,都必须确保字符串数据的来源比对 from_string
.
Either the return value of
FirstStruct::get
has been allocated on the stack or it has been allocated on the heap.
比这更棘手。 return 值在堆栈上总是 。也就是说,Option<&str>
在堆栈上占据了 space。 &str
可能包含指向在堆栈或堆上分配的内容的指针,此代码不知道。您所知道的是,指向的值保证在该特定 FirstStruct
项目的生命周期内有效。
您不拥有字符串,因此无法转让所有权。
I can't move FirstStruct because it is from another library (rustc-serialize
我不确定你的意思。如果你有一个对象,那么你可以将它嵌入到你的对象中。它来自另一个板条箱的事实并没有发挥作用。如果你有对某物的引用,那么你仍然可以捕获引用,但是你的对象必须比引用存在更短的时间(这样它就永远不会失效)。
Unwrapping Option, updating to a string and rewrapping in Option is a lot of boilerplate.
你见过Option::map
吗?它使这种事情变得非常简洁。结合From
,可以写一个很短的东西把一个Option<&str>
转换成Option<String>
:
// fn is just to establish some types, you'd just use the `.map` call in real code
fn foo(a: Option<&str>) -> Option<String> {
a.map(From::from)
}