2017-04-22 77 views
1

我正在使用Rust中的控制檯提示界面編寫進程內存掃描程序。Rust和性狀參考(特徵對象?)中的多態性

我需要掃描儀類型,如winapi掃描儀或ring0驅動程序掃描儀,所以我試圖實現多態性。

我在這一刻以下結構:

pub trait Scanner { 
    fn attach(&mut self, pid: u32) -> bool; 
    fn detach(&mut self); 
} 

pub struct WinapiScanner { 
    pid: u32, 
    hprocess: HANDLE, 
    addresses: Vec<usize> 
} 

impl WinapiScanner { 
    pub fn new() -> WinapiScanner { 
     WinapiScanner { 
      pid: 0, 
      hprocess: 0 as HANDLE, 
      addresses: Vec::<usize>::new() 
     } 
    } 
} 

impl Scanner for WinapiScanner { 
    fn attach(&mut self, pid: u32) -> bool { 
     let handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid) }; 
     if handle == 0 as HANDLE { 
      self.pid = pid; 
      self.hprocess = handle; 
      true 
     } else { 
      false 
     } 
    } 

    fn detach(&mut self) { 
     unsafe { CloseHandle(self.hprocess) }; 
     self.pid = 0; 
     self.hprocess = 0 as HANDLE; 
     self.addresses.clear(); 
    } 
} 

今後,我將有更多的掃描儀類型除了WinapiScanner,所以,如果我理解正確的話,我應該使用特性引用(&Scanner)實現多態。我試圖創建Scanner對象像這樣(注意註釋):

enum ScannerType { 
    Winapi 
} 

pub fn start() { 
    let mut scanner: Option<&mut Scanner> = None; 
    let mut scanner_type = ScannerType::Winapi; 

    loop { 
     let line = prompt(); 
     let tokens: Vec<&str> = line.split_whitespace().collect(); 
     match tokens[0] { 

      // commands 
      "scanner" => { 
       if tokens.len() != 2 { 
        println!("\"scanner\" command takes 1 argument") 
       } else { 
        match tokens[1] { 
         "list" => { 
          println!("Available scanners: winapi"); 
         }, 
         "winapi" => { 
          scanner_type = ScannerType::Winapi; 
          println!("Scanner type set to: winapi"); 
         }, 
         x => { 
          println!("Unknown scanner type: {}", x); 
         } 
        } 
       } 
      }, 
      "attach" => { 
       if tokens.len() > 1 { 
        match tokens[1].parse::<u32>() { 
         Ok(pid) => { 
          scanner = match scanner_type { 
           // ---------------------- 
           // Problem goes here. 
           // Object, created by WinapiScanner::new() constructor 
           // doesn't live long enough to borrow it here 
           ScannerType::Winapi => Some(&mut WinapiScanner::new()) 
           // ---------------------- 
          } 
         } 
         Err(_) => { 
          println!("Wrong pid"); 
         } 
        } 
       } 
      }, 

      x => println!("Unknown command: {}", x) 
     } 
    } 
} 

fn prompt() -> String { 
    use std::io::Write; 
    use std::io::BufRead; 

    let stdout = io::stdout(); 
    let mut lock = stdout.lock(); 
    let _ = lock.write(">> ".as_bytes()); 
    let _ = lock.flush(); 
    let stdin = io::stdin(); 
    let mut lock = stdin.lock(); 
    let mut buf = String::new(); 
    let _ = lock.read_line(&mut buf); 
    String::from(buf.trim()) 
} 

這不是一個完整的程序;我只粘貼了重要的部分。

我在做什麼錯,我如何實現我想要的Rust?

回答

5

特徵對象必須在指針後面使用。但引用不是唯一的指針; Box也是一個指針!

let mut scanner: Option<Box<Scanner>> = None; 

scanner = match scanner_type { 
    ScannerType::Winapi => Some(Box::new(WinapiScanner::new())) 
}