2015-02-09 84 views
3

前言:我已經完成了我的研究,並且知道它確實不是一個好主意/也不是慣用的Rust有一個。完全開放給解決這個問題的其他方法的建議。如何創建一個全局可變布爾狀態標誌

背景:我有一個連接到websocket的控制檯應用程序,一旦連接成功,服務器發送一個「連接」消息。我有發件人,接收者是獨立的線程,一切都很好。 connect()調用一個循環開始並在終端中發出提示,表示應用程序已準備好接收來自用戶的輸入。

問題:問題是,當前的執行調用流程連接,然後立即顯示提示,然後應用程序收到來自服務器的消息,指出它已連接。

如何我會在高級語言解決這個問題:將全球布爾(我們就叫它ready),一旦應用程序是「準備」,然後顯示提示。

我怎麼覺得這可能看起來拉斯特:

//Possible global ready flag with 3 states (true, false, None) 
let ready: Option<&mut bool> = None; 

fn main(){ 
    welcome_message(); //Displays a "Connecting..." message to the user 

    //These are special callback I created and basically when the 
    //message is received the `connected` is called. 
    //If there was an error getting the message (service is down) 
    //then `not_connected` is called. *This is working code* 
    let p = mylib::Promise::new(connected, not_connected); 

    //Call connect and start websocket send and receive threads 
    mylib::connect(p); 

    //Loop for user input 
    loop { 
     match ready { 
      Some(x) => { 
       if x == true { //If ready is true, display the prompt 
        match prompt_input() { 
         true => {}, 
         false => break, 
        } 
       } else { 
        return; //If ready is false, quit the program 
       } 
      }, 
      None => {} //Ready is None, so continue waiting 
     } 
    } 
} 

fn connected() -> &mut bool{ 
    println!("Connected to Service! Please enter a command. (hint: help)\n\n"); 
    true 
} 

fn not_connected() -> &mut bool{ 
    println!("Connection to Service failed :("); 
    false 
} 

問: 你將如何解決這個問題的鏽?我曾嘗試將它傳遞給所有庫方法調用,但遇到了有關在FnOnce()閉包中借用不可變對象的一些主要問題。

+0

雖然我會鼓勵你*不*使用全局可變狀態,我想如果我沒有至少指向[這個答案]是失職(http://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton),告訴你如何做到這一點。 – Shepmaster 2015-02-09 02:45:05

回答

3

這聽起來像是你想要兩個線程通過頻道進行通信。看看這個例子:

use std::thread; 
use std::sync::mpsc; 
use std::time::Duration; 

enum ConsoleEvent { 
    Connected, 
    Disconnected, 
} 

fn main() { 
    let (console_tx, console_rx) = mpsc::channel(); 

    let socket = thread::spawn(move || { 
     println!("socket: started!"); 

     // pretend we are taking time to connect 
     thread::sleep(Duration::from_millis(300)); 

     println!("socket: connected!"); 
     console_tx.send(ConsoleEvent::Connected).unwrap(); 

     // pretend we are taking time to transfer 
     thread::sleep(Duration::from_millis(300)); 

     println!("socket: disconnected!"); 
     console_tx.send(ConsoleEvent::Disconnected).unwrap(); 

     println!("socket: closed!"); 
    }); 

    let console = thread::spawn(move || { 
     println!("console: started!"); 

     for msg in console_rx.iter() { 
      match msg { 
       ConsoleEvent::Connected => println!("console: I'm connected!"), 
       ConsoleEvent::Disconnected => { 
        println!("console: I'm disconnected!"); 
        break; 
       } 
      } 
     } 
    }); 

    socket.join().expect("Unable to join socket thread"); 
    console.join().expect("Unable to join console thread"); 
} 

在這裏,有3個線程在作怪:

  1. 主線程。
  2. 從「套接字」中讀取的線程。
  3. 用於與用戶交互的線程。

這些線程中的每一個都可以維護它自己的非共享的狀態。這使得每個線程的推理變得更容易。線程使用channel來安全地在它們之間發送更新。穿過線程的數據封裝在一個枚舉中。

當我跑,我得到

socket: started! 
console: started! 
socket: connected! 
console: I'm connected! 
socket: disconnected! 
socket: closed! 
console: I'm disconnected! 
+0

是的,這非常合理。再一次非常感謝你)。這是一個更乾淨簡潔的方法。正如我讀過的所有內容所說,通常比使用全球更好,我根本想不起來。 – SnareChops 2015-02-09 02:40:47