iDu*_*Jie 1 temporary lifetime rust
我无法调用Foo::new(words).split_first()以下代码
fn main() {
let words = "Sometimes think, the greatest sorrow than older";
/*
let foo = Foo::new(words);
let first = foo.split_first();
*/
let first = Foo::new(words).split_first();
println!("{}", first);
}
struct Foo<'a> {
part: &'a str,
}
impl<'a> Foo<'a> {
fn split_first(&'a self) -> &'a str {
self.part.split(',').next().expect("Could not find a ','")
}
fn new(s: &'a str) -> Self {
Foo { part: s }
}
}
Run Code Online (Sandbox Code Playgroud)
编译器会给我一个错误信息
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:8:17
|
8 | let first = Foo::new(words).split_first();
| ^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
9 |
10 | println!("{}", first);
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Run Code Online (Sandbox Code Playgroud)
如果我绑定Foo::new(words)first 的值,那么调用该split_first方法没有问题.
这两种调用方法应该直观地相同,但在某种程度上是不同的.
\n\n
Foo::new(words).split_first()将被粗略地解释为
let tmp = Foo::new(words);\nlet ret = tmp.split_first();\ndrop(tmp);\nret\nRun Code Online (Sandbox Code Playgroud)\n\n如果 Rust 允许你这样做,则 中的引用将ret 指向[edit: will be allowed by the type of split_firstto point *] 到现在删除的值中tmp。因此,Rust 不允许这样做,\xe2\x80\x99 是一件好事。如果您用 C++ 编写了等效的单行代码,则\xe2\x80\x99d 会默默地获得未定义的行为。
通过let自己编写绑定,您可以将删除延迟到范围末尾,从而扩展了\xe2\x80\x99 可以安全地拥有这些引用的区域。
有关更多详细信息,请参阅Rust 参考中的临时生命周期。
\n\n* 编辑:正如Jmb 所指出的,这个特定示例中的真正问题是类型
\n\nfn split_first(&\'a self) -> &\'a str\nRun Code Online (Sandbox Code Playgroud)\n\n\xe2\x80\x99 不够具体,更好的解决方案是将类型细化为:
\n\nfn split_first<\'b>(&\'b self) -> &\'a str\nRun Code Online (Sandbox Code Playgroud)\n\n可以缩写为:
\n\nfn split_first(&self) -> &\'a str\nRun Code Online (Sandbox Code Playgroud)\n\n这传达了预期的保证,即返回的引用不会指向Foo<\'a>(仅指向字符串本身)。
简短的回答:去除'a一生的self参数split_first:fn split_first(&self) -> &'a str(游乐场).
答案很长:
当你编写这段代码时:
struct Foo<'a> {
part: &'a str,
}
impl<'a> Foo<'a> {
fn new(s: &'a str) -> Self {
Foo { part: s }
}
}
Run Code Online (Sandbox Code Playgroud)
您告诉编译器所有Foo实例都与某个生命周期相关,该生命周期'a必须等于或短于作为参数传递的字符串的生命周期Foo::new.该生命周期'a 可能与每个Foo实例的生命周期不同.当你写下:
let words = "Sometimes think, the greatest sorrow than older";
Foo::new(words)
Run Code Online (Sandbox Code Playgroud)
编译器推断生命周期'a必须等于或短于生命周期words.除非存在任何其他约束,否则编译器将使用生命周期words,'static因此它对程序的整个生命周期都有效.
当您添加以下定义时split_first:
fn split_first(&'a self) -> &'a str
Run Code Online (Sandbox Code Playgroud)
您正在添加一个额外的约束:您说它'a必须等于或短于生命周期self.因此,编译器将占用words临时Foo实例的生命周期和生命周期中较短的一个,这是临时实例的生命周期.@ AndersKaseorg的答案解释了为什么这不起作用.
通过消除'a对寿命self参数,我去相关 'a从临时的寿命,所以编译器可以再次推断'a是的寿命words,这是足够长的程序协同工作.
| 归档时间: |
|
| 查看次数: |
323 次 |
| 最近记录: |