为什么Foo<'a,P<'b>>与Foo2<'a>不一样?

时间:2017-05-24 12:56:42

标签: rust

use std::collections::{HashMap, HashSet};

pub struct P<'a> {
    x: &'a str
}

pub struct Foo<'a, T> {
    callbacks: Vec<Box<'a + FnMut(&T)>>
}

impl<'a, T> Foo<'a, T>{
    pub fn foo(&mut self, payload: T) {
    }

}

pub struct Foo2<'a> {
    callbacks: Vec<Box<'a + FnMut(&P)>>
}

impl<'a> Foo2<'a>{
    pub fn foo(&mut self, payload: P) {
    }

}


struct Bar<'a, 'b> {
    x: Foo<'a, P<'b>>,
    y: Foo2<'a>,
    data: HashMap<String, String>
}


impl<'a, 'b> Bar<'a, 'b> {
    // fn test(&mut self) {
    //     // Cannot infer an appropriate lifetime.
    //     match self.data.get("foo") {
    //         Some(x) => {
    //             let p = P {x};
    //             self.x.foo(p);
    //         },
    //         None => {}
    //     }
    // }

    fn test2(&mut self) {
        match self.data.get("foo") {
            Some(x) => {
                let p = P {x};
                self.y.foo(p);
            },
            None => {}
        }
    }

}

Playground。我每晚都在使用rustc 1.19.0。

为什么test2有效但test没有?如何正确制作通用结构Foo

我认为此示例不涉及Why can't I store a value and a reference to that value in the same struct?,并且不重复。

1 个答案:

答案 0 :(得分:2)

什么是'a,什么是'b

如果我们找出失败的案例(请注意我为self引入了一段时间以使其更容易):

pub struct P<'a> {
    x: &'a str
}

pub struct Foo<'a, T> {
    callbacks: Vec<Box<'a + FnMut(&T)>>
}

impl<'a, T> Foo<'a, T>{
    pub fn foo(&mut self, payload: T) {
    }
}

struct Bar<'a, 'b> {
    x: Foo<'a, P<'b>>,
    data: HashMap<String, String>
}


impl<'a, 'b> Bar<'a, 'b> {
    fn test<'c>(&'c mut self) {
        // Cannot infer an appropriate lifetime.
        match self.data.get("foo") {
            Some(x) => {
                let p = P {x};
                self.x.foo(p);
            },
            None => {}
        }
    }
}

这里的问题是当您实例化 Bar时,您修复 'a'b是什么。

具体来说,这个生命周期不是'c,这完全不相关。

编译器看到:

  • self.x.foo的参数必须为P<'b>
  • 它的类型为P<'unknown>,其中'unknown的任何生命周期少于而不是'c
  • 它的类型为P<'unknown>,因此'unknown必须大于'b
  • 'b'c无关。

并且不知道'unknown应该是什么。

可能的解决方案是避免修复'b

pub struct Foo<'a> {
    callbacks: Vec<Box<'a + FnMut(&P)>>,
}

impl<'a> Foo<'a> {
    pub fn foo(&mut self, payload: P) {}
}

struct Bar<'a> {
    x: Foo<'a>,
    data: HashMap<String, String>,
}

注意:此时,'a似乎也是多余的。

然而,这需要我们修复T,因为当使用类型参数(就像我们使用Foo<'a, T>时)时,我们需要完全指定类型,从而命名{{{ 1}}将包含。