2017-07-03 4 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[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... 

:コンパイラの提案をしようとすると

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, _)| { 

が、私はこれを取得ここではいくつかの(部分)のコードは、この問題を実証していますRefCellでステートをラップしようとしましたが(ステート自体の直後にRefCellを作成します)、コンパイラはを移動しようとしているので同様の移動エラーが発生しますをクライアントコンテキストを作成するクロージャに追加します。

答えて

1

あなたはかなりRefCellに近いです。今すぐ必要なのは、RefCellをラップしてRcをクローンし、RefCellをキャプチャしないように、Rcが必要です。

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年代は、今、あなたはおそらく先に行くとRcとを格納するあなたのClientContext構造体を変換する必要がありますことをご注意>代わりに&mut Stateの。いくつかのもののために&mut Stateを使用し続けることは可能かもしれませんが、&mut StateRefMutの生涯に拘束され、次の閉鎖が実行されるまで生き続けるなら、借用はパニックになります。 try_の亜種を使用してください)。

また心に留めておくあなたがあなたの反応器内の複数のスレッドを持つようにしたい決定した場合、あなたはそれが必要なのは非常に自然な変換である、ArcRcを変更する必要がある、とMutexからRefCellます。

関連する問題