我正在从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}}
答案 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
实施PenHookInner
。 PenHookInner
将包含删除钩子所需的数据。由于issue 11406,我们无法Drop
直接在PenHook
上实施#[unsafe_destructor]
。如果我们不需要在pen
的实现中访问drop()
借用的指针,那么我们可以使用单独的结构来干净地解决它。
我让Pen::new()
返回Pen
而不是Box<Pen>
,因为没有理由将结果包装好。如果呼叫者想要设置该值,他们可以在呼叫站点使用box
。
...我即将以一个关于哪种类型实现Clone
的公开问题结束,但后来我在上游图书馆的下一个版本中读到了关于Pen
消失的评论。我想你想要克隆笔和钩子。显然,使用这种结构,你将无法轻易做到这一点。您可以轻松地在Clone
上实施Pen
,但对于PenHook
,您还需要其他内容。
答案 1 :(得分:0)
您可以为Pen
一个NoCopy
字段,以防止它被隐式复制。
不确定这是否是你所要求的。