使用非静态引用的方法静态声明的结构

Statically declared struct with method taking a non-static reference

我正在尝试使用静态定义的结构 (Outer)。 Outer 有一个引用结构 (Context) 的方法,其中 Context 的生命周期短于 Outer.

下面的代码也可以在这个rust playground找到:

use std::marker::PhantomData;

trait Doable {
    fn do_thing(&self) -> u8;
}

struct Stuff(u8);

struct Context<'a> {
    stuff: &'a mut Stuff,
}

impl<'a> Doable for Context<'a> {
    fn do_thing(&self) -> u8 {
        self.stuff.0 + 1
    }
}

struct Outer<'a, T> {
    buffer: &'a mut [u8],
    used: u8,
    phantom_context: PhantomData<T>,
}

impl<'a, T> Outer<'a, T>
where T: Doable
{
    fn use_context(&'a mut self, context: &mut T) {
        self.used = context.do_thing();
    }
}

fn use_outer_with_context(context: &mut Context) {
    static mut buffer: [u8; 64] = [0u8; 64];
    static mut outer: Outer<'static, Context> = unsafe {
        Outer {
            buffer: &mut buffer,
            used: 0,
            phantom_context: PhantomData,
        }
    };

    unsafe {outer.use_context(context)};
}

fn main() {

    let mut s = Stuff(4);

    let context = Context {stuff: &mut s};

    use_outer_with_context(&mut context);

}

当我尝试编译这段代码时,出现以下错误:

error[E0621]: explicit lifetime required in the type of `context`
  --> src/lib.rs:45:31
   |
35 | fn use_outer_with_context(context: &mut Context) {
   |                                    ------------ help: add explicit lifetime `'static` to the type of `context`: `&mut Context<'static>`
...
45 |     unsafe {outer.use_context(context)};
   |                               ^^^^^^^ lifetime `'static` required

我很难理解为什么 Rust 编译器 expects/requires context 的生命周期与 outer 的生命周期相同 ('static)。 outercontext 长寿应该没问题,因为它只在 use_context() 方法的生命周期内使用 context 吗?

此处省略了生命周期:

static mut outer: Outer<'static, Context> = unsafe {
                                 ^^^^^^^

由于这是一个静态变量,编译器将推断出 'static 生命周期,因此 outer 的完整类型是 Outer<'static, Context<'static>>.

因此,在对use_context的调用中,context参数的类型是&mut Context<'static>。但是,use_outer_with_context 正在传递 &mut Context<'a>'a 在源代码中被省略)。

这里的问题是 T 需要提前指定,而实际上,由于 Context<'a> 中的生命周期,T 可能会因调用而异。 =33=]

可以通过将 T 从结构移动到 use_context 方法来使您的示例工作。

struct Outer<'a> {
    buffer: &'a mut [u8],
    used: u8,
}

impl<'a> Outer<'a>
{
    fn use_context<T>(&mut self, context: &mut T)
    where
        T: Doable,
    {
        self.used = context.do_thing();
    }
}

fn use_outer_with_context(context: &mut Context) {
    static mut buffer: [u8; 64] = [0u8; 64];
    static mut outer: Outer<'static> = unsafe {
        Outer {
            buffer: &mut buffer,
            used: 0,
        }
    };

    unsafe {
        outer.use_context(context);
    }
}

注意:我在 Outer::use_context 上将 &'a mut self 更改为 &mut self'a 是不必要的,会导致编译器错误。

您可能不想 T 移动到单个方法是有原因的。在那种情况下,我不知道可行的解决方案。如果 Rust 有 generic associated types,那么可以用生命周期参数 pending application 来表示 Context。不幸的是,从 Rust 1.41.0 开始,泛型关联类型并未实现。