如何“克隆克隆”一种不允许移动的类型?

时间:2014-10-14 02:35:59

标签: rust

我正在从C库中包装对象,该库在对象上生成事件。为了将低级事件映射到高级事件,我需要传递高级对象的地址。

这一切都有效。

mod c
{
    enum Pen; // opaque struct
}

struct Pen
{
    pen: *mut c::Pen,
    event_hook: Option<Box<FnMut<(&mut Pen, EventDetails), ()>>>,
}

impl Pen
{
    fn new() -> Box<Pen>
    {
        let rv = box Pen{pen: ..., event_hook: None};
        ... set up hook to use rv's raw address in a callback and forward to event_hook ...;
        rv
    }
}

impl Drop for Pen
{
    fn drop(&mut self)
    {
        ...;
    }
}

当我尝试impl Clone时会出现问题。我不能impl Clone for Box<Pen>因为它与liballoc中的实现冲突。我不能impl Clone for Pen,因为在设置低级别挂钩后地址会发生变化。

克隆此类型的能力非常重要。我可以impl Pen提供实际返回框的名为 .clone().clone_from()的函数,但这会阻止任何人将此对象传递给需要{{的函数1}}

2 个答案:

答案 0 :(得分:1)

您需要将Pen结构的创建与挂钩和取消挂钩分开。

use std::kinds::marker::NoCopy;

mod c
{
    pub struct Pen; // opaque struct
}

struct Pen
{
    pen: *mut c::Pen,
    //event_hook: Option<Box<FnMut<(&mut Pen, EventDetails), ()>>>, // FIXME: this type does not compile
    _no_copy: NoCopy
}

struct PenHookInner {
    event_hook: Option<()> // TODO: maybe event_hook should move here from Pen?
}

struct PenHook<'a> {
    pen: &'a Pen,
    inner: PenHookInner,
}

impl Pen
{
    fn new() -> Pen
    {
        let rv = Pen { pen: 0 as *mut c::Pen /*, event_hook: None*/, _no_copy: NoCopy };
        rv
    }

    fn hook(&self) -> PenHook {
        // TODO: set up hook to use self.pen's raw address in a callback and forward to event_hook
        PenHook {
            pen: self,
            inner: PenHookInner { event_hook: None }
        }
    }
}

impl Drop for PenHookInner {
    fn drop(&mut self) {
        // TODO: remove the hook
    }
}

fn main() {
    let pen = Pen::new();
    let pen_hook = pen.hook();
    //drop(pen); //~ error: cannot move out of `pen` because it is borrowed
}

Pen包含NoCopy字段,以使结构不可隐式复制。如果您需要实施Drop来释放“原生”笔,那么您不需要NoCopy字段。 (实现Drop的类型隐式不是Copy。)

创建PenHook时,它会借用对Pen的引用。这可以防止在Pen存在时移动或删除PenHook。只要存在PenHook对象,就无法移动或删除Pen

如果Pen没有NoCopy字段,则仍然可以隐式复制它:删除它,您将看到drop(pen);行编译。那是因为drop()收到了pen的副本并删除了它。由于Pen未在此示例中实现Drop,因此这是一个无操作。

我们现在为Drop实施PenHookInnerPenHookInner将包含删除钩子所需的数据。由于issue 11406,我们无法Drop直接在PenHook上实施#[unsafe_destructor]。如果我们不需要在pen的实现中访问drop()借用的指针,那么我们可以使用单独的结构来干净地解决它。

我让Pen::new()返回Pen而不是Box<Pen>,因为没有理由将结果包装好。如果呼叫者想要设置该值,他们可以在呼叫站点使用box

...我即将以一个关于哪种类型实现Clone的公开问题结束,但后来我在上游图书馆的下一个版本中读到了关于Pen消失的评论。我想你想要克隆笔和钩子。显然,使用这种结构,你将无法轻易做到这一点。您可以轻松地在Clone上实施Pen,但对于PenHook,您还需要其他内容。

答案 1 :(得分:0)

您可以为Pen一个NoCopy字段,以防止它被隐式复制。

不确定这是否是你所要求的。