返回位置具有通用关联类型的Impl特征导致生命周期错误

chp*_*pio 7 rust

我需要在结构中存储fn(I) -> O(其中IO可以是引用)'staticO需要是具有'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
}
Run Code Online (Sandbox Code Playgroud)

操场

Pet*_*aro 5

据我所知,编译器的错误消息具有误导性,它实际需要的是显式定义的关联类型:

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

对这个问题的出色回答:为什么编译器不推断 impl trait 返回值的关联类型的具体类型?提供了足够的信息,说明为什么实际上需要这样做。

另请参阅Rust 问题 #42940 - impl-trait 返回类型受所有输入类型参数的限制,即使是不必要的

您可以使用泛型类型参数而不是返回 ,impl在这种情况下您不必指定关联类型:

fn map<T: IntoState>(i: T) -> T {
    i
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信我为这个问题找到了正确的 GitHub 问题:https://github.com/rust-lang/rust/issues/42940 (3认同)
  • 我确实认为这是编译器的一个缺点(我不会讨论它是否应该被称为“错误”)。这个生命周期在存在返回类型的_关联类型_中被捕获的事实是相当出乎意料的。我可以理解为什么在编译器中以这种方式实现它,但是从编写 Rust 代码的软件开发人员的角度来看,这种行为是没有意义的。 (2认同)