【问题标题】:Rust Callback: Error: Lifetime 'static requiredRust 回调:错误:Lifetime 'static required
【发布时间】:2018-08-27 19:51:44
【问题描述】:

我正在尝试编写一个将回调作为参数的通用函数。但是,我总是收到以下错误消息:

error[E0310]: the parameter type `C` may not live long enough
  --> src/lib.rs:36:5
   |
17 | pub fn helper<'de, Q, S, C>(mut state : State, callback : C) -> Box<HandlerFuture>
   |                          - help: consider adding an explicit lifetime bound `C: 'static`...
...
36 |     Box::new(f)
   |     ^^^^^^^^^^^
   |
note: ...so that the type `futures::Then<futures::stream::Concat2<hyper::Body>, futures::FutureResult<(gotham::state::State, hyper::Response), (gotham::state::State, gotham::handler::HandlerError)>, [closure@src/lib.rs:24:15: 34:10 callback:&C, state:gotham::state::State]>` will meet its required lifetime bounds
  --> src/lib.rs:36:5
   |
36 |     Box::new(f)
   |     ^^^^^^^^^^^

这是产生错误消息的最小可编译示例:

extern crate futures;
extern crate gotham;
extern crate hyper;
extern crate mime;
extern crate serde;
extern crate serde_json;

use futures::{future, Future, Stream};
use gotham::handler::{HandlerFuture, IntoHandlerError};
use gotham::http::response::create_response;
use gotham::state::{FromState, State};
use hyper::{Body, StatusCode};
use mime::APPLICATION_JSON;
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};

pub fn helper<'de, Q, S, C>(mut state : State, callback : C) -> Box<HandlerFuture>
    where Q : Deserialize<'de>,
          S : Serialize,
          C : Fn(Q) -> S
{
    let f = Body::take_from(&mut state)
        .concat2()
        .then(|full_body| match full_body {
            Ok(valid_body) => {
                let body_content = String::from_utf8(valid_body.to_vec()).unwrap();
                let body_json = from_str::<Q>(&body_content).unwrap();
                let resp_json = callback(body_json);
                let resp_content = to_string(&resp_json).unwrap().into_bytes();
                let res = create_response(&state, StatusCode::Ok, Some((resp_content, APPLICATION_JSON)));
                future::ok((state, res))
            }
            Err(e) => return future::err((state, e.into_handler_error()))
        });

    Box::new(f)
}

按照 rustc 的建议将 C : 'static 添加到 where 子句中,我收到以下错误消息:

error[E0597]: `body_content` does not live long enough
  --> src/lib.rs:28:48
   |
28 |                 let body_json = from_str::<Q>(&body_content).unwrap();
   |                                                ^^^^^^^^^^^^ borrowed value does not live long enough
...
33 |             }
   |             - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'de as defined on the function body at 17:1...
  --> src/lib.rs:17:1
   |
17 | / pub fn helper<'de, Q, S, C>(mut state : State, callback : C) -> Box<HandlerFuture>
18 | |     where Q : Deserialize<'de>,
19 | |           S : Serialize,
20 | |           C : Fn(Q) -> S,
...  |
37 | |     Box::new(f)
38 | | }
   | |_^

这是我Cargo.toml的最小内容:

[package]
name = "test"
version = "0.1.0"

[dependencies]
futures = "0.1"
gotham = "0.2"
hyper = "0.11"
mime = "0.3"
serde = "1.0"
serde_json = "1.0"

【问题讨论】:

  • 为什么你认为你的代码应该可以工作?您的返回值是否捕获了该引用?参考是否存在足够长的时间?编译器将如何验证这一点?
  • 你为什么决定首先参考?
  • @Shepmaster 我相信我的代码应该可以工作,因为如果我不接受回调而是调用函数,它确实可以正常工作。不知道你在哪里问我为什么要引用,如果是callback的参数,改成Fn(Q)而不是Fn(&amp;Q)也没什么区别
  • 我在问你为什么选择&amp;Fnthat 引用的寿命有多长?编译器如何验证它的寿命是否足够长?
  • @Shepmaster 好吧,如果我不参考,我会收到一条错误消息,指出在编译时不知道回调的大小 (the trait bound `for&lt;'r&gt; std::ops::Fn(&amp;'r Q) -&gt; S + 'static: std::marker::Sized` is not satisfied)

标签: rust lifetime


【解决方案1】:

在 rustc 的建议和this article 的帮助下,我能够解决所有错误:

  1. 我在where 子句中添加了C : 'static
  2. 我更改了闭包 |full_body| 使其变为 move
  3. 我将绑定类型从Deserialize&lt;'de&gt; 更改为DeserializeOwned

我最终得到了这个似乎有效的代码:

pub fn helper<Q, S, C>(mut state : State, callback : C) -> Box<HandlerFuture>
    where Q : DeserializeOwned,
          S : Serialize,
          C : Fn(Q) -> S,
          C : 'static
{
    let f = Body::take_from(&mut state)
        .concat2()
        .then(move |full_body| match full_body {
            Ok(valid_body) => {
                let body_content = String::from_utf8(valid_body.to_vec()).unwrap();
                let body_json = from_str::<Q>(&body_content).unwrap();
                let resp_json = callback(body_json);
                let resp_content = to_string(&resp_json).unwrap().into_bytes();
                let res = create_response(&state, StatusCode::Ok, Some((resp_content, APPLICATION_JSON)));
                future::ok((state, res))
            }
            Err(e) => return future::err((state, e.into_handler_error()))
        });

    Box::new(f)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2018-01-25
    • 1970-01-01
    • 2021-10-10
    相关资源
    最近更新 更多