2017-07-03 34 views
4

我正在使用rust-websocket和基于Tokio的异步系统在Rust中编写websocket服务器。我可以为客户提供服务,但是,我无法弄清楚如何在客户端之间共享可变状态。这里是一些(部分)代码演示此问题:使用async(tokio)在客户端之间共享可变状态rust-websocket

let mut core = Core::new().unwrap(); 
let handle = core.handle(); 
let server = Server::bind("localhost:62831", &handle).unwrap(); 

let mut state = State{ 
    ... 
}; 

let f = server.incoming() 
    .map_err(|InvalidConnection {error, ..}| error) 
    .for_each(|upgrade, _)| { 
     let f = upgrade.accept() 
      .and_then(|s, _| { 
       let ctx = ClientContext{ 
        // some other per-client values 
        state: &mut state, 
       } 
       ... 
       return s.send(Message::binary(data).into()) 
        .and_then(move |s| Ok(s, ctx)); // this could be the complete wrong way to insert context into the stream 
      }).and_then(|s, ctx| { 
       // client handling code here 
      }); 

      handle.spawn(f 
       .map_err(...) 
       .map(...) 
      ); 
      return Ok(()) 
    }); 

core.run(f).unwrap(); 

本该代码中的错误:

error[E0373]: closure may outlive the current function, but it borrows `**state`, which is owned by the current function 
    --> src/main.rs:111:27 
    | 
111 |     .and_then(|(s, _)| { 
    |       ^^^^^^^^ may outlive borrowed value `**state` 
... 
114 |       state: &mut state, 
    |          ----- `**state` is borrowed here 
    | 
help: to force the closure to take ownership of `**state` (and any other referenced variables), use the `move` keyword, as shown: 
    |     .and_then(move |(s, _)| { 

当试图编译器的建议下,我得到这个:

error[E0507]: cannot move out of captured outer variable in an `FnMut` closure 
    --> src/main.rs:111:27 
    | 
111 |     .and_then(move |(s, _)| { 
    |       ^^^^^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure 

error: `state` does not live long enough 
    --> src/main.rs:114:37 
    | 
114 |       state: &mut state, 
    |          ^^^^^ does not live long enough 
... 
122 |     }) 
    |     - borrowed value only lives until here 
    | 
    = note: borrowed value must be valid for the static lifetime... 

我也尝试在RefCell(在状态本身之后创建RefCell)中包装状态,但是,编译器会给出类似的移动错误,因为它会尝试移动RefCell到创建客户端上下文的闭包中。

回答

1

你很接近RefCell。你现在需要的是一个Rc来包装RefCell,所以你可以克隆Rc而不是捕获RefCell本身。

let shared_state = Rc::new(RefCell::new(State::new()))); 
incoming().for_each(move |s, _| { 
    let shared_state = shared_state.clone(); // Left uncaptured 
    shared_state.borrow_mut().do_mutable_state_stuff(); // Could panic 
}); 

注意,因为你正在使用Rc的和RefCell的现在,你可能需要继续前进,你的ClientContext结构转换为存储一个RC>代替&mut State的。在某些情况下可能会继续使用&mut State,但是您的&mut State将与RefMut的生命周期相关联,并且如果在下一次关闭运行之前保持活动状态,则借入者会恐慌(或者如果您失败使用try_变体)。

同时请记住,如果你决定要在你的反应堆多个线程,你只需要改变RcArc,并RefCellMutex,这是很自然的转换在需要时。

相关问题