【问题标题】:Adding a closure within a '&self' method to an attribute in a struct将“&self”方法中的闭包添加到结构中的属性
【发布时间】:2023-03-22 05:20:01
【问题描述】:

考虑以下示例代码:

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate jsonrpc_core as rpc;

#[derive(Serialize, Deserialize)]
struct Test {
    var: u32,
}

struct TestRpc {
    test: Test,
    rpc_io_handler: rpc::IoHandler,
}

impl TestRpc {
    fn new() -> Self {
        let ret = Self {
            test: Test { var: 1 },
            rpc_io_handler: rpc::IoHandler::new(),
        };
        ret.register_rpc_methods();
        ret
    }

    fn register_rpc_methods(&self) {
        let get_var = |_params: rpc::Params| match rpc::to_value(&self.test) {
            Ok(x) => Ok(x),
            Err(_) => Err(rpc::Error::internal_error()),
        };
        self.rpc_io_handler.add_method("get_var", get_var);
    }

    fn get_var_test(&self, msg: &str) -> Option<String> {
        self.rpc_io_handler.handle_request_sync(msg)
    }
}

fn main() {
    let test = TestRpc::new();
    let request = r#"{"jsonrpc": "2.0", "method": "get_var", "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":{"var":1},"id":1}"#;
    assert_eq!(test.get_var_test(request), Some(response.to_owned()));
}

具有以下 'rpc::IoHandler::add_method' 的方法签名

pub fn add_method<F>(&mut self, name: &str, method: F)
where
    F: RpcMethodSimple,

method is from jsonrpcRpcMethodSimple一样。

当我尝试编译时出现以下错误

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:26:27
   |
26 |           let mut get_var = |_params: rpc::Params | {
   |  ___________________________^
27 | |             match rpc::to_value(&self.test) {
28 | |                 Ok(x) => Ok(x),
29 | |                 Err(_) => Err(rpc::Error::internal_error())
30 | |             }
31 | |         };
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 25:5...
  --> src/main.rs:25:5
   |
25 | /     fn register_rpc_methods(&self) {
26 | |         let mut get_var = |_params: rpc::Params | {
27 | |             match rpc::to_value(&self.test) {
28 | |                 Ok(x) => Ok(x),
...  |
32 | |         self.rpc_io_handler.add_method("get_var", get_var);
33 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&TestRpc
              found &&TestRpc
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:26:27: 31:10 self:&&TestRpc]` will meet its required lifetime bounds
  --> src/main.rs:32:29
   |
32 |         self.rpc_io_handler.add_method("get_var", get_var);
   |                             ^^^^^^^^^^

是否可以在不更改 crate 方法的情况下使用此方法(rpc::IoHandler::add_method)?我在 Rust 中苦苦挣扎;有没有简单的方法来限制闭包的生命周期?

【问题讨论】:

  • 我手头没有编译器,但是您是否尝试将moveing self.test(分别是clone)放入闭包中?
  • 是否可以添加对闭包的引用?这将允许您设置像 let get_var = &amp;'a mut |...| {/*your code*/}; 这样的生命周期参数,并为自己设置相同的生命周期参数:&amp;'a self
  • 我相信How to return a future combinator with &amp;self的答案已经回答了您的问题。如果您不同意,请edit您的问题解释差异。否则,我们可以将此问题标记为已回答。

标签: rust closures self lifetime json-rpc


【解决方案1】:

我对 jsonrpc 的内部不太熟悉,但是 jsonrpc 库是用 Tokio 以完全异步的方式实现的。尽管您调用同步请求处理,但在内部它仍然异步执行请求并简单地阻塞您的线程,直到它完成。这样做的缺点是 Tokio 不能保证在任务执行器中安排你的闭包。因此,与任何self 相比,任何此类闭包的生命周期都更多地与执行者相关。

在上面的代码中,您捕获了对self 的引用,但不能保证在执行闭包时self 仍然存在。因此,您必须 move 闭包使用的任何数据。此外,闭包必须是 Send 才能与 Tokio 一起使用,因此您不能简单地使用 Rc 并将副本移动到闭包中。

就您而言,我所知道的最简单的方法是将test 更改为输入Arc&lt;Test&gt;。然后更改闭包定义以将变量的副本移动到闭包中。您还遇到了一些可变性问题,这是一个完整的编译示例:

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate jsonrpc_core as rpc;

use std::borrow::Borrow;
use std::sync::Arc;

#[derive(Serialize, Deserialize)]
struct Test {
    var: u32,
}

struct TestRpc {
    test: Arc<Test>,
    rpc_io_handler: rpc::IoHandler,
}

impl TestRpc {
    fn new() -> Self {
        let mut ret = Self {
            test: Arc::new(Test { var: 1 }),
            rpc_io_handler: rpc::IoHandler::new(),
        };
        ret.register_rpc_methods();
        ret
    }

    fn register_rpc_methods(&mut self) {
        let test_clone = self.test.clone();
        let get_var = move |_params: rpc::Params| match rpc::to_value(test_clone.borrow() as &Test)
        {
            Ok(x) => Ok(x),
            Err(_) => Err(rpc::Error::internal_error()),
        };
        self.rpc_io_handler.add_method("get_var", get_var);
    }

    fn get_var_test(&self, msg: &str) -> Option<String> {
        self.rpc_io_handler.handle_request_sync(msg)
    }
}

fn main() {
    let test = TestRpc::new();
    let request = r#"{"jsonrpc": "2.0", "method": "get_var", "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":{"var":1},"id":1}"#;
    assert_eq!(test.get_var_test(request), Some(response.to_owned()));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多