Добавление замыкания в методе «& self» к атрибуту в структуре - PullRequest
0 голосов
/ 27 октября 2018

Рассмотрим следующий пример кода:

#[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,

Метод из 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);
   |                             ^^^^^^^^^^

Возможно ли использовать этот метод (rpc::IoHandler::add_method) без изменения метода в ящике?Я борюсь с жизнями в Русте;Есть ли простой способ ограничить время жизни замыкания?

1 Ответ

0 голосов
/ 28 октября 2018

Я не слишком знаком с внутренностями 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()));
}
...