【问题标题】:Polymorphism in Rust and trait references (trait objects?)Rust 中的多态性和特征引用(特征对象?)
【发布时间】:2017-04-22 23:00:08
【问题描述】:

我正在用 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,我还会有更多的扫描器类型,所以,如果我理解正确的话,我应该使用特征引用(&amp;Scanner)来实现多态性。我正在尝试像这样创建 Scanner 对象(注意 cmets):

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

【问题讨论】:

    标签: rust polymorphism


    【解决方案1】:

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

    let mut scanner: Option<Box<Scanner>> = None;
    
    scanner = match scanner_type {
        ScannerType::Winapi => Some(Box::new(WinapiScanner::new()))
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 1970-01-01
      • 2017-05-23
      • 2022-10-05
      • 1970-01-01
      • 2015-05-26
      • 1970-01-01
      相关资源
      最近更新 更多