[英]“error: closure may outlive the current function” but it will not outlive it
[英]Why the mutable reference parameter of a closure doesn't outlive the function call?
我正在使用cssparser
crate 來解析一些 CSS 代碼。 我想創建一個能夠解析type
function 的閉包。 作為第一步,我以這種方式創建了一個非常簡單的代碼:
use cssparser::{Parser, ParserInput};
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser| {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}
我收到以下錯誤:
error[E0282]: type annotations needed for the closure `fn(&mut Parser<'_, '_>) -> std::result::Result<&str, _>`
--> src/main.rs:9:43
|
9 | p.expect_function_matching("type")?;
| ^ cannot infer type of error for `?` operator
|
= note: `?` implicitly converts the error value into a type implementing `From<BasicParseError<'_>>`
正如在這個答案中所讀,我添加了我的閉包的返回類型:
let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
};
我仍然有一個我不明白的錯誤:
error: lifetime may not live long enough
--> src/main.rs:9:9
|
8 | let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
| - ---------------------------------------- return type of closure is std::result::Result<&str, BasicParseError<'2>>
| |
| has type `&mut Parser<'1, '_>`
9 | p.expect_function_matching("type")?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
顯然'1
是在'2
之前發布的。 我的閉包參數是參考,怎么會這樣? 在調用我的關閉后它應該還活着,對吧?
我試圖明確地注釋我的對象的生命周期,但我無法找到正確的方法來做到這一點; 我總是有一個“未聲明的生命周期”錯誤。 例如:
let parse_type = |p: &mut Parser<'i, '_>| -> Result<&str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
不幸的是, 閉包不能聲明生命周期 arguments ,這將需要傳達此 function 的正確生命周期。 將其移至 function 會產生更好的錯誤:
use cssparser::{Parser, ParserInput};
fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
}
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let res = parse_type(&mut parser);
}
error[E0106]: missing lifetime specifier
--> src\main.rs:3:41
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&'a str, cssparser::BasicParseError> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^
error[E0106]: missing lifetime specifier
--> src\main.rs:3:58
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^^^^^^^^^^^^^^^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&str, cssparser::BasicParseError<'a>> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
編譯器會盡量自動推斷生命周期,但是p
涉及三個生命周期&'1 Parser<'2, '3>
,所以它不知道生命周期&'_ str
或BasicParseError<'_>
應該被推斷為。
查看Parser::expect_function_matching
的簽名,您可能想要:
fn parse_type<'i>(p: &mut Parser<'i, '_>) -> Result<&'i str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
}
當然,雖然@kmdreko 所說的一切都是絕對正確的,但用 function 替換您的閉包僅在您沒有捕獲任何環境時才有效 - 如果是這種情況,您可以簡單地聲明parse_type
是一個 function 指針和相關的type 和 Rust 將相應地強制關閉:
let parse_type: for<'i> fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = |p| {
p.expect_function_matching("type")?;
Ok("OK")
};
但是,如果您的閉包確實捕獲了環境,那么我想@kmdreko 方法的擴展將是定義一個結構來保存該環境,然后對該結構進行一些實現來定義適當的方法。 但這是很多咕嚕聲。 您可以改為使parse_type
成為Fn
特征之一的特征 object 並使用上述方法的類似物:
let parse_type: &dyn for<'i> Fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = &|p| {
p.expect_function_matching("type")?;
Ok("OK")
};
理論上,這會在調用閉包時增加一個額外的間接層,但我認為實際上優化器會刪除它(除非你至少在函數之間傳遞閉包)。 無論如何,在大多數情況下,這將是一筆非常不相關的費用。
最后,如果您的input_string
實際上來自 function 參數,那么您將能夠在 function 簽名中命名其生命周期並直接在您的閉包定義中使用它:
fn example<'i>(input_string: &'i str) {
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser<'i, '_>| -> Result<_, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.