簡體   English   中英

為什么閉包的可變引用參數不會超過 function 調用?

[英]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> ,所以它不知道生命周期&'_ strBasicParseError<'_>應該被推斷為。

查看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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM