Rust和特征引用中的多态性(特征对象?)

时间:2017-04-22 23:00:09

标签: rust polymorphism

我正在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中实现我想要的东西?

1 个答案:

答案 0 :(得分:5)

必须在指针后面使用特征对象。但引用并不是唯一的指针; Box也是一个指针!

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

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