如何引用特征并仍然使用原始结构?

时间:2015-02-11 09:53:27

标签: rust

我的目标是有一个引用计数结构,它在一个上下文中被称为特征,在另一个上下文中被称为特定类型。最好用代码解释:

#![feature(box_syntax)]

use std::rc::Rc;
use std::cell::RefCell;

trait Employee {
    fn be_managed(&mut self);
}

struct Human;

impl Human {
    fn be_human(&mut self) {
        println!("I'm just a human who needs a mutable self sometimes");
    }
}

impl Employee for Human {
    fn be_managed(&mut self) {
        println!("Off to the salt mines");
    }
}

struct Manager {
    my_employee: Rc<RefCell<Box<Employee + 'static>>>, //'
}

fn main() {
    let mut human1 = Rc::new(RefCell::new(box Human as Box<Employee>));

    let manager1 = Manager {
        my_employee: human1.clone(), // This works due to cast above
    };

    manager1.my_employee.borrow_mut().be_managed();

    human1.borrow_mut().be_human(); // But we can't be human anymore



    let mut human2 = Rc::new(RefCell::new(box Human));

    let manager2 = Manager {
        my_employee: human2.clone(), // This doesn't work
    };

    manager2.my_employee.borrow_mut().be_managed();

    human2.borrow_mut().be_human();
}

我希望Manager能够将任何实现Employee特征的结构作为my_employee,但是其他引用仍然可以调用原始对象上的其他方法,即be_human

现在我从上面的代码中收到以下错误:

src/main.rs:37:25: 37:35 error: type `core::cell::RefMut<'_, Box<Employee>>` does not implement any method in scope named `be_human`
src/main.rs:37     human1.borrow_mut().be_human(); // But we can't be human anymore
                                       ^~~~~~~~~~
src/main.rs:44:22: 44:36 error: mismatched types:
 expected `alloc::rc::Rc<core::cell::RefCell<Box<Employee + 'static>>>`,
    found `alloc::rc::Rc<core::cell::RefCell<Box<Human>>>`
(expected trait Employee,
    found struct `Human`) [E0308]
src/main.rs:44         my_employee: human2.clone(), // This doesn't work
                                    ^~~~~~~~~~~~~~

在这种情况下,正确的方法是什么?

1 个答案:

答案 0 :(得分:3)

免责声明:在此回答中,我将假设您不愿意使用enum因为您希望Employee开启。

这个问题涉及使用动态多态的每种语言,传统的答案是Visitor Pattern

但它并不完全理想,因为它引入了依赖性,所以如果有必要,你可以使用Acyclic Visitor Pattern;但是我建议你在深入研究之前先从裸骨访客那里开始。

trait EmployeeVisitor {
    fn visit_employee(&self, e: &Employee);
    fn visit_human(&self, h: &Human);
}

trait Employee {
    fn accept(&self, v: &EmployeeVisitor) {
        v.visit_employee(self);
    }
}

impl Employee for Human {
    fn accept(&self, v: &EmployeeVisitor) {
        v.visit_human(self);
    }
 }

这是传统的“每个问题都可以用一层间接来解决”,它带来了传统的另一层间接问题。