[英]How might I return a reference to a new collection inside of a closure in Rust?
[英]How to return a reference in Rust Closure
我有以下 rust 代碼無法編譯。
struct Person {
name : String,
age : u8,
}
fn main() {
let p = Person{ name: "Nobody".to_string(), age : 24};
let age = |p : &Person| p.age;
let name = |p : &Person | &p.name;
println! ("name={}, age={}" , name(&p), age(&p));
}
並且編譯器給出了以下錯誤信息。
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:11:31
|
11 | let name = |p : &Person | &p.name;
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 11:16...
--> src/main.rs:11:16
|
11 | let name = |p : &Person | &p.name;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:11:31
|
11 | let name = |p : &Person | &p.name;
| ^^^^^^^
note: but, the lifetime must be valid for the expression at 2:29...
--> src/main.rs:13:5
|
13 | println! ("name={}, age={}" , name(&p), age(&p));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so type `(&&std::string::String, &u8)` of expression is valid during the expression
--> src/main.rs:13:5
|
13 | println! ("name={}, age={}" , name(&p), age(&p));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error
我試圖為name
關閉添加生命周期。
let name<'a> = |p : &'a Person | -> &'a String { &'a p.name };
但仍然有編譯器錯誤
Compiling playground v0.0.1 (/playground)
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
--> src/main.rs:12:13
|
12 | let name<'a> = |p : &'a Person | -> &'a String { &'a p.name };
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
error: aborting due to previous error
只是想知道如何編寫正確的代碼。
對我來說更重要的是了解問題的根源找到解決方法,所以一步一步來。 讓我們從有效的東西開始:
struct Person {
name: String,
age: u8,
}
fn get_name<'a>(person: &'a Person) -> &'a str {
&person.name
}
fn main() {
let p = Person {
name: "Nobody".to_string(),
age: 24,
};
let age = |p: &Person| p.age;
let name = get_name;
println!("name={}, age={}", name(&p), age(&p));
}
使用函數而不是閉包時沒有問題。 在這種情況下,編譯器能夠檢查生命周期要求是否正常。
但是當嘗試對name
使用閉包時:
let name = |p : &Person | &p.name;
你得到了cannot infer an appropriate lifetime
錯誤。
為什么?
閉包捕獲其環境:編譯器必須創建一些不透明的結構,並且此類結構必須是可調用的。
我不完全了解內部細節,但是在對閉包進行脫糖時會創建以下內容:
struct OpaqueType<'a> {
// a PhantomData because you don't capure nothing
// just to make explicit that struct lifetime bind to environment
// if you would had captured some integer:
// captured_int: &'a i32,
captured_int: PhantomData<&'a i32>,
}
impl<'a> OpaqueType<'a> {
fn call<'b>(&'b self, person: &'a Person) -> &'a str {
&person.name
}
}
看看call
很明顯,當一個 clusure 參數是一個引用時,有兩個不相關的生命周期在起作用。
另請注意,在您的情況下,不聲明參數類型並使用輔助函數get_name
,有效:
// let name = |p| &p.name; // does not work, not enough info to infer p type
let name = |p| get_name(p);
我的猜測是,在這種情況下,編譯器遵循一些推理路徑,能夠以生命周期按預期有界的方式進行脫糖。
另一種解決方案是為您的閉包提供顯式類型。 不幸的是,您不能使用它的實際類型,但您可以將其轉換為函數指針。
請記住,問題在於編譯器無法正確推斷輸出的生命周期與輸入的生命周期相關(它可能是此錯誤的一個實例,但我完全不確定)。 我們可以通過使生命周期顯式來解決這個問題。
struct Person {
name: String,
age: u8,
}
fn main() {
let p = Person {
name: "Nobody".to_string(),
age: 24,
};
let age = |p: &Person| p.age;
// Our only changes are right here.
let name: for<'a> fn(&'a Person) -> &'a String = |p: &Person| &p.name;
println!("name={}, age={}", name(&p), age(&p));
}
事實上,有可能比這稍微不那么明確。 編譯器可以很好地確定輸入和輸出的類型。 這只是它遇到麻煩的生命周期。 所以用let name: for<'a> fn(&'a _) -> &'a _ = |p: &Person| &p.name;
替換該行let name: for<'a> fn(&'a _) -> &'a _ = |p: &Person| &p.name;
let name: for<'a> fn(&'a _) -> &'a _ = |p: &Person| &p.name;
也適用(游樂場) 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.