将“&self”方法中的闭包添加到结构中的属性
Adding a closure within a '&self' method to an attribute in a struct
考虑以下示例代码:
#[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 jsonrpc
RpcMethodSimple
.
当我尝试编译这个时出现以下错误
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 的生命周期中苦苦挣扎;有没有简单方法来限制闭包的生命周期?
我对 jsonrpc 的内部结构不太熟悉,但是 jsonrpc 库是用 Tokio 以完全异步的方式实现的。尽管您调用同步请求处理,但在内部它仍然异步执行请求并简单地阻塞您的线程直到它完成。这样做的缺点是 Tokio 无法保证在任务执行器中安排您的闭包。因此,任何此类闭包的生命周期都比任何 self
.
更依赖于执行者。
在上面的代码中,您捕获了对 self
的引用,但无法保证 self
在执行闭包时仍然存在。因此,您必须 move
闭包使用的任何数据。此外,闭包必须 Send
才能与 Tokio 一起使用,因此您不能简单地使用 Rc
并将副本移动到闭包中。
对于您的情况,我知道的最简单方法是将 test
更改为键入 Arc<Test>
。然后更改闭包定义以将变量的副本移动到闭包中。您还遇到了一些可变性问题,这是一个完整的编译示例:
#[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()));
}
考虑以下示例代码:
#[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 jsonrpc
RpcMethodSimple
.
当我尝试编译这个时出现以下错误
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 的生命周期中苦苦挣扎;有没有简单方法来限制闭包的生命周期?
我对 jsonrpc 的内部结构不太熟悉,但是 jsonrpc 库是用 Tokio 以完全异步的方式实现的。尽管您调用同步请求处理,但在内部它仍然异步执行请求并简单地阻塞您的线程直到它完成。这样做的缺点是 Tokio 无法保证在任务执行器中安排您的闭包。因此,任何此类闭包的生命周期都比任何 self
.
在上面的代码中,您捕获了对 self
的引用,但无法保证 self
在执行闭包时仍然存在。因此,您必须 move
闭包使用的任何数据。此外,闭包必须 Send
才能与 Tokio 一起使用,因此您不能简单地使用 Rc
并将副本移动到闭包中。
对于您的情况,我知道的最简单方法是将 test
更改为键入 Arc<Test>
。然后更改闭包定义以将变量的副本移动到闭包中。您还遇到了一些可变性问题,这是一个完整的编译示例:
#[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()));
}