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

时间:2019-06-17 17:49:00

标签: rust

我需要在fn(I) -> O结构中存储I(其中O'static可以作为引用)。 O必须是具有'static通用关联类型的特征,该类型也存储在结构中。 IO都没有存储在该结构内部,因此它们的生存期无关紧要。但是编译器仍在抱怨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
}

playground

2 个答案:

答案 0 :(得分:3)

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

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

对问题的极好的回答:Why does the compiler not infer the concrete type of an associated type of an impl trait return value?提供了有关为何真正需要此原因的足够信息。

更新:您可以使用通用类型参数代替返回impl,在这种情况下,您不必指定关联的类型:

fn map<T: IntoState>(i: T) -> T {
    i
}

答案 1 :(得分:2)

显然,这里到底发生了什么,所以我会感到困惑,所以我将尝试将我的评论解释成一个简短的答案。

这里的问题是函数map()的原型:

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

这指定map()的返回类型是实现IntoState some 类型,并且具有未指定的关联类型State。返回类型具有一个带有参数i生存期的生命周期参数;我们将其称为生存期'a,并将其称为完整返回类型T<'a>。现在,此返回类型的关联类型State<T<'a> as IntoState>::State,由'a参数化。尽管trait定义中有'static声明,但编译器当前仍无法从关联类型中删除此生命周期参数。通过将关联类型显式指定为String,编译器将仅使用显式指定的类型String而不是<T<'a> as IntoState>::State,因此lifetime参数消失了,并且不会出错不再。

this Github issue中讨论了此编译器缺陷。