время жизни должно быть допустимым для статического времени жизни, чтобы типы были совместимы - PullRequest
0 голосов
/ 05 сентября 2018

Мне известно о Откуда взялись «статические времена жизни» и Невозможно определить подходящее время жизни для авторефера из-за противоречивых требований

Но я все еще не понимаю проблему, с которой столкнулся:

use std::ops::Index;

trait Stack<T> {
    fn as_slice(&self) -> &[T];
}

impl<T> Index<usize> for Stack<T> {
    type Output = T;
    fn index(&self, i: usize) -> &T {
        &self.as_slice()[i]
    }
}

trait Core {
    fn stack(&self) -> &Stack<usize>;
    fn bad(&mut self) -> usize {
       self.stack()[0]
    }
    fn good(&mut self) -> usize {
       self.stack().as_slice()[0]
    }
}

fn main() {}

В приведенном выше коде good() не дает ошибок, но bad() жалуется с:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:18:14
|
18 |         self.stack()[0]
|              ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 17:5...
--> src/main.rs:17:5
|
17 | /     fn bad(&mut self) -> usize {
18 | |         self.stack()[0]
19 | |     }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:18:9
|
18 |         self.stack()[0]
|         ^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
        expected std::ops::Index<usize>
            found std::ops::Index<usize>

В этом коде нет Box, и я не знаю, откуда исходит статическое время жизни.

Редактировать: из-за проб и ошибок я обнаружил, что компилятор предполагает, что Stack + 'статический. Следующий код компилируется. Но почему? Пожалуйста, укажите мне какой-нибудь документ.

impl<'b, T> Index<usize> for Stack<T> + 'b {
    type Output = T;
    fn index<'a>(&'a self, i: usize) -> &'a T {
        &self.as_slice()[i]
    }
}

1 Ответ

0 голосов
/ 06 сентября 2018

Вы реализуете черту (Index) для объекта черты (Stack<T>).

Ссылка Rust сообщает:

Поскольку объект признака может содержать ссылки, время жизни этих ссылок должно быть выражено как часть объекта признака. Эта жизнь написана как Черта + 'a. Существуют значения по умолчанию, которые позволяют сделать вывод об этой жизни с разумным выбором.

Если Вы не определяете время жизни, компилятор принимает значение по умолчанию, в этом случае предполагается 'static (подробное объяснение см. здесь )

Ваш код эквивалентен:

impl<T> Index<usize> for Stack<T> + 'static {
    type Output = T;
    fn index(&self, i: usize) -> &T {
        &self.as_slice()[i]
    }
}

Чтобы устранить ошибку компиляции cannot infer an appropriate lifetime for autoref due to conflicting requirements, просто объявите, что метод stack() возвращает объект свойства с 'static продолжительностью жизни.

trait Core {
    fn stack(&self) -> &'static Stack<usize>;
    fn bad(&mut self) -> usize {
       self.stack()[0]
    }
    fn good(&mut self) -> usize {
       self.stack().as_slice()[0]
    }
}

В противном случае объявите общее время жизни для объекта признака Stack<T>, которое подразумевает Index:

impl<'a, T> Index<usize> for Stack<T> + 'a {
    type Output = T;
    fn index(&self, i: usize) -> &T {
        &self.as_slice()[i]
    }
}

trait Core {
    fn stack(&self) -> &Stack<usize>;
    fn bad(&mut self) -> usize {
       self.stack()[0]
    }
    fn good(&mut self) -> usize {
       self.stack().as_slice()[0]
    }
}

В этот момент вы должны спросить: почему использование as_slice() в good() работает, а использование index() в bad() - нет?

Чтобы понять это, попробуйте прочитать комментарии, встроенные в MVCE ниже.

use std::ops::Index;

trait Stack<T> {
    fn as_slice(&self) -> &[T];
}

// equivalent to: impl<T> Index<usize> for Stack<T>
// just to expose the conflicting requirements error
// the right declaration is:
// impl<'a, T> Index<usize> for Stack<T> + 'a
impl<T> Index<usize> for Stack<T> + 'static {
    type Output = T;
    fn index(&self, i: usize) -> &T {
        &self.as_slice()[i]
    }
}

trait Core {
    fn stack(&self) -> &Stack<usize>;
    fn bad<'a>(&'a mut self) -> usize {
       //self.stack()[0] syntactic sugar for:
       *self.stack().index(0)

       // self.stack() returns a trait object with a lifetime bound != 'static
       // but Stack impl for Index requires a 'static lifetime bound: 
       // COMPILE ERROR: cannot infer an appropriate lifetime for
       // autoref due to conflicting requirements
    }
    fn good<'a>(&'a mut self) -> usize {
       // self.stack() returns a trait object with 'a lifetime bound
       // this is congruent with as_slice() lifetime requirements
       // see Catasta::as_slice() impl below
       // NO COMPILE ERROR
       self.stack().as_slice()[0]
    }
}

struct Catasta<T> {
    pila: [T;4]
}

impl<T> Stack<T> for Catasta<T> {

    fn as_slice<'a>(&'a self) -> &'a [T] {
        &self.pila
    }
}

struct RealCore {
    stk: Catasta<usize>
}

impl Core for RealCore {
    fn stack(&self) -> &Stack<usize> {
        &self.stk
    }
}

fn main() {
    let mut core = RealCore {stk: Catasta {pila: [100, 2, 3, 4]} };
    println!("pos [0] item: {}", core.good());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...