Признак Impl с родственным ассоциированным типом в возвращаемой позиции вызывает ошибку времени жизни - PullRequest
6 голосов
/ 17 июня 2019

Мне нужно хранить fn(I) -> O (где I & O могут быть ссылками) в структуре 'static. O должен быть признаком с общим типом 'static, этот тип также хранится в структуре. Ни I, ни O не хранятся внутри структуры, поэтому их время жизни не должно иметь значения. Но компилятор все еще жалуется на то, что I не живет достаточно долго.

trait IntoState {
    type State: 'static;

    fn into_state(self) -> Self::State;
}

impl IntoState for &str {
    type State = String;

    fn into_state(self) -> Self::State {
        self.to_string()
    }
}

struct Container<F, S> {
    func: F,
    state: S,
}

impl<I, O> Container<fn(I) -> O, O::State>
where
    O: IntoState,
{
    fn new(input: I, func: fn(I) -> O) -> Self {
        // I & O lives only in the next line of code. O gets converted into
        // a `'static` (`String`), that is stored in `Container`.
        let state = func(input).into_state();
        Container { func, state }
    }
}

fn map(i: &str) -> impl '_ + IntoState {
    i
}

fn main() {
    let _ = {
        // create a temporary value
        let s = "foo".to_string();

        // the temporary actually only needs to live in `new`. It is
        // never stored in `Container`.
        Container::new(s.as_str(), map)
        // ERR:        ^ borrowed value does not live long enough
    };
    // ERR: `s` dropped here while still borrowed
}

детская площадка

Ответы [ 2 ]

3 голосов
/ 17 июня 2019

Насколько я могу судить, сообщение об ошибке компилятора вводит в заблуждение, что на самом деле требует явно определенного связанного типа:

fn map(i: &str) -> impl '_ + IntoState<State = String> {
    i
}

Отличный ответ на вопрос: Почему компилятор не выводит конкретный тип связанного типа возвращаемого значения признака impl? предоставляет достаточно информации о том, почему это действительно необходимо.

Обновление: Вы можете использовать параметр универсального типа вместо возврата impl, в этом случае вам не нужно указывать связанный тип:

fn map<T: IntoState>(i: T) -> T {
    i
}
2 голосов
/ 18 июня 2019

По-видимому, все еще существует некоторая путаница в отношении того, что именно здесь происходит, поэтому я постараюсь перевести мои комментарии в короткий ответ.

Проблема здесь в прототипе функции map():

fn map(i: &str) -> impl '_ + IntoState

Указывает, что типом возврата map() является некоторый тип, реализующий IntoState, с неопределенным связанным типом State. Возвращаемый тип имеет параметр времени жизни с временем жизни аргумента i; давайте назовем это время жизни 'a, а полный тип возврата T<'a>. Связанный тип State этого типа возврата теперь равен <T<'a> as IntoState>::State, который параметризован 'a. В настоящее время компилятор не может удалить этот параметр времени жизни из ассоциированного типа, несмотря на объявление 'static в определении черты. Если явно указать связанный тип как String, компилятор будет просто использовать явно указанный тип String вместо <T<'a> as IntoState>::State, поэтому параметр времени жизни пропадет, и мы больше не получим ошибку.

Этот недостаток компилятора обсуждается в этой проблеме Github .

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