我正在写一个包含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>
,重构我的代码等等。
答案 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
值,这可能会导致健全性问题。