Статически объявленная структура с методом, принимающим нестатическую c ссылку - PullRequest
3 голосов
/ 24 февраля 2020

Я пытаюсь использовать структуру (Outer), которая определена статически. У Outer есть метод, который принимает ссылку на структуру (Context), где время жизни Context короче, чем Outer.

Следующий код также можно найти на этой ржавая площадка :

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

Мне трудно понять, почему компилятор ржавчины ожидает / требует, чтобы время жизни context было таким же, как у outer ('static). Разве это не нормально для outer пережить context, так как он использует context только для времени жизни метода use_context()?

1 Ответ

3 голосов
/ 24 февраля 2020

Здесь есть допустимое время жизни:

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

Поскольку это переменная stati c, компилятор выведет время жизни 'static, поэтому полный тип outer равен * 1006. *.

Следовательно, при вызове use_context тип параметра context равен &mut Context<'static>. Однако use_outer_with_context передает &mut Context<'a> ('a исключается из источника).

Проблема здесь в том, что T необходимо указать заранее, тогда как на самом деле T может меняться от вызова к вызову из-за времени жизни в Context<'a>.

Ваш образец можно заставить работать, переместив 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);
    }
}

Примечание: я изменил &'a mut self на &mut self на Outer::use_context; 'a не требуется и может привести к ошибкам компилятора.

Может быть причина, по которой вы не захотите переходить T к отдельному методу. В таком случае, тогда я не знаю жизнеспособного решения. Если бы Rust имел generi c связанных типов , тогда можно было бы представить Context с приложением, ожидающим параметр времени жизни. К сожалению, родовые c связанные типы не реализованы с Rust 1.41.0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...