Почему время жизни моего возвращенного свойства impl ограничено временем жизни его ввода?

Пытаясь понять, почему какой-то мой код не компилируется, я создал следующий минимальный тест.

Я пытаюсь написать функцию, которая получает что-то вроде &Vec<i32> и возвращает что-то, что можно преобразовать в итератор через i32.

Вывод не содержит ничего заимствованного из ввода. Я намерен, чтобы выход имел более длительный срок службы, чем вход.

На мой взгляд новичка, похоже, что это должно работать.

fn error_1<'a, I: IntoIterator<Item=&'a i32>>(_: I) -> impl IntoIterator<Item=i32> + 'static {
    vec![1]
}

Но когда я проверяю, может ли вывод жить дольше, чем ввод...

fn test_e1() {
    let v = vec![3];
    let a = error_1(&v);
    drop(v); // DROP v BEFORE a.. should be ok!?
}

Я получаю эту ошибку.

error[E0505]: cannot move out of `v` because it is borrowed
 --> src/lib.rs:8:10
  |
7 |     let a = error_1(&v);
  |                     -- borrow of `v` occurs here
8 |     drop(v); // DROP v BEFORE a.. should be ok!?
  |          ^ move out of `v` occurs here
9 | }
  | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl IntoIterator<Item = i32>`

Итак, Rust обеспокоен тем, что возможная реализация IntoIterator МОЖЕТ позаимствовать «v»? Ссылка на игровую площадку - неработающий код
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=41ef3bce0157cc23f824f20eb0651bd9

Я попытался поэкспериментировать с этим дальше...
Что меня абсолютно сбивает с толку, так это то, почему следующий тест компилируется просто отлично... Кажется, у него та же проблема, но rust с удовольствием его скомпилирует.

fn fine_1<'a, I: IntoIterator<Item=i32>>(_: &I) -> impl IntoIterator<Item=i32> + 'static {
    vec![1]
}

fn test_f1() {
    let v = vec![3];
    let a = fine_1(&v);
    drop(v); // DROP v BEFORE a.. should be ok!?
}

Ссылка на игровую площадку для измененного, рабочего кода
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7e92549aa4e741c4dd0aae289afcf9db

Может ли кто-нибудь помочь мне объяснить, что не так с первым кодом?
Как я могу указать, что время жизни возвращаемого типа совершенно не связано со временем жизни параметра?

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

    fn error_fn<'a, I: IntoIterator<Item=&'a i32>>(_: I) -> impl Fn() + 'static{
        || {}
    }

    fn test_fn() {
        let v = vec![3];
        let a = error_fn(&v);
        drop(v);
    }

Я не ищу обходной путь... Я могу реорганизовать код.
Цель здесь состоит в том, чтобы научиться... Это обнажает пробел в моем понимании жизни...
Что-то, что до недавнего времени я думал, что прибил :D

Стоит отметить, что если я изменю входные данные на конкретный тип, а не на трейт.. `_: &Vec, то все снова компилируется нормально.

КАЖЕТСЯ время жизни на ассоциированном типе черты, что все ломает... Я только не понимаю, почему!??

Вы никогда не прибиваете жизни. Кроме, возможно, одного или двух человек во всем мире. Всегда есть какой-нибудь интересный угловой случай. И я говорю это как человек, который проверял реализацию контролера заимствований :)

Chayim Friedman 22.11.2022 12:00
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
4
1
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

impl Trait в позиции возвращаемого типа неявно фиксируются параметры универсального типа. Это означает, что он ограничен их сроком службы. Насколько я знаю, нет возможности отказаться от этого.

Он не фиксирует параметры времени жизни, поэтому вариант без использования 'a компилируется нормально.

В этом выпуске приведены некоторые подробности.

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

#![feature(type_alias_impl_trait)]

type Res = impl IntoIterator<Item = i32>;
fn error_1<'a, I: IntoIterator<Item = &'a i32>>(_: I) -> Res {
    vec![1]
}

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

Другие вопросы по теме