如何要求 Rust 方法的泛型移动参数与对象一样长?

How to require generic moved parameters to a Rust method live as long as the object?

我正在编写一个包含 Lua 解释器的 Rust 程序,我需要将几种类型的对象保存到 Lua 管理的内存(用户数据)中,以便 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 不需要类型参数,而是有一个通用的 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>、重构我的代码等方面做了一些聪明的 and/or 可怕的事情。

您可以在 LuaState<'a> 中嵌入一个假生命周期 'a 并在 hide() 中要求 T: 'a:

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

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

我不是 100% 确定这是正确的,但它似乎适用于您提供的示例。 (full playpen)

消除 PhantomData 的缺点是编译器不再理解 LuaState 在逻辑上拥有各种 TRc<T>。如果(看起来)删除 LuaState 可能会删除 T 值,这可能会导致健全性问题。