如果对象需要通用移动参数到Rust方法?

时间:2016-03-12 00:47:46

标签: rust lifetime

我正在写一个包含Lua解释器的Rust程序,我需要将几种类型的对象保存到Lua管理的内存(userdata)中,这样Lua就会调用它们上的方法。通常它们会像Rc<T>一样,并且会知道正确类型的适当方法包装器。

如果我一次只接受一种类型,我可以安全地将物品传递给Lua州:

struct Foo<'a> {
    badref: &'a u32,
}

struct LuaState<T> {
    /* ... */
    _foo: PhantomData<T>,
}

impl<T> LuaState<T> {
    fn hide(&mut self, foo: T) {}
}

fn main() {
    let mut l = LuaState{_foo: PhantomData};
    {
        let n = 7u32;
        let foo = Foo { badref: &n };
        /* Correctly fails to compile, since l can keep a (hidden)
         * reference to n after its scope ends */
        l.hide(foo);
    }
}

我真的希望LuaState不需要type参数,而是使用通用的hide方法:

struct LuaState {
    /* ... */
}
impl LuaState {
    fn hide<T>(&mut self, foo: T) {}
}

...它不会为包含不会超过T的引用的任何LuaState进行编译,就像我一次只能处理单个类型一样。我接近了:

trait LuaAble<'a> {}
impl<'a> LuaAble<'a> for Foo<'a> {}

struct LuaState<'a> {
    marker: PhantomData<LuaAble<'a>>,
}

impl<'a> LuaState<'a> {
    fn hide<T: LuaAble<'a>>(&mut self, foo: T) {}
}

这几乎有效;它会停止上面的悬空参考示例,但也可能错误地实现了特征:

impl<'a, 'b> LuaAble<'b> for Foo<'a> {}

这再次让隐藏的悬空引用案例编译,因为生命周期不再绑定在一起了。

有没有办法阻止按值传递给某个方法,这个方法不能像&self一样长寿?我对任何想法持开放态度,无论他们是否做了一些聪明和/或可怕的特质,生命周期,for<'a>,重构我的代码等等。

1 个答案:

答案 0 :(得分:3)

您可以在'a中嵌入假终身LuaState<'a>,并在T: 'a中需要hide()

struct LuaState<'a> {
    _foo: PhantomData<&'a ()>,
}

impl<'a> LuaState<'a> {
    fn hide<T: 'a>(&mut self, foo: T) {}
}

我不是100%确定这是正确的,但它似乎与你给出的例子有关。 (full playpen)

消除PhantomData的缺点是编译器不再理解LuaState逻辑上拥有各种Rc<T>的{​​{1}}。如果(因为它似乎是)放弃T可能会降低LuaState值,这可能会导致健全性问题。