2017-05-24 42 views
0

感谢您纠正我提问的方式。我做了几次修改,以使代码可编译。处理`进入`泛型时出现生锈问题

use std::marker::PhantomData; 

struct Brace { 
    x: i32, 
} 

impl Brace { 
    fn transform(&self, n: i32) -> Devil { 
     Devil { 
      hp: self.x + n, 
      weapon: None, 
     } 
    } 
} 

struct Bar<'a> { 
    tasty: &'a str, 
} 

struct Foo<'a, B> 
    where B: 'a + Into<Bar<'a>> 
{ 
    brace: Brace, 
    buz: Option<B>, // buz is of generic type B, and is able to be turned into bar. 
    phantom: PhantomData<&'a B>, // A marker that is used to resolve 'unused lifetime parameter a' 
} 

impl<'a, B: Into<Bar<'a>>> Foo<'a, B> { 
    fn transform_and_arm(self) { 
     // line B 
     let brace1: Brace = self.brace; 
     let mut devil: Devil = brace1.transform(12345); // line A 
     let buz = self.buz.unwrap(); 
     // Before this line, it passes the compiler. 
     // Uncommenting the following line causes compiler to argue that the brace1 at line A doesn't live long enough. It says that borrowed value must be valid for the lifetime 'a as defined on the body at line B, but the borrowed value only lives until line C. 
     // devil = devil.arm(buz); 
     // Although adding the above line fails, making the weapon directly won't cause the compiler to complain. 
     // Uncommenting the following line passes compiler. 
     // let weapon = buz.into(); 

     // The compiler stops the devil from arming itself before I even try to write the following line. 
     // devil.slay_the_world(); 
    } // line C 
} 

struct Devil<'a> { 
    hp: i32, 
    weapon: Option<Bar<'a>>, 
} 

impl<'a> Devil<'a> { 
    fn arm<B: Into<Bar<'a>>>(mut self, biu: B) -> Devil<'a> { 
     self.weapon = Some(biu.into()); 
     self 
    } 

    fn slay_the_world(self) { 
     unimplemented!() 
    } 
} 

transform_and_arm()方法被设计成通过带走bracebuz消耗的Foo一个实例。它呼吁brace.transform()使brace a Devil。它通过喂魔鬼buz.unwrap()加强魔鬼。

问题是,调用let weapon = buz.into();是合法的,而调用devil = devil.arm(buz);会导致生命期问题。

看来问题与生命期息息相关。如果没有魔鬼,那么所有这些问题都会消失。

回答

0

编辑我以前的回答没有很好地解释这个问题。这是另一个尝试。

您遇到此问题是因为transform存在缺陷。为了找出原因,让我们看看使用寿命期,编译器已经推断transform

fn transform<'a>(&'a self, n: i32) -> Devil<'a> 

我们可以看到,编译器已经决定放弃返回Devil相同的寿命作为传递给函数的引用self

现在,让我们来看看Devil

struct Devil<'a> { 
    hp: i32, 
    weapon: Option<Bar<'a>>, 
} 

我们可以看到,Devil的一生参数与它相关的weapon

回首transform,但是......

fn transform<'a>(&'a self, n: i32) -> Devil<'a> { 
    Devil { 
     hp: self.x + n, 
     weapon: None, 
    } 
} 

...很明显的是,weapon,这是Devil的生命周期参数的唯一目的,不以任何方式与参考到self,所以&selfDevil的生存期应该有与彼此无关

这导致的问题时,Devil分配实际的武器,因为我们可能想给Devil一个weapon有不同的使用寿命,而且没有理由认为我们不应该能够做到这一点。

而且,当前实施的transform禁止返回的Devil超出对self的引用,并且不一定是这种情况。

要解决该问题,明确标注transform,使之清楚,&self和返回Devil有无关寿命:

fn transform<'a, 'b>(&'a self, n: i32) -> Devil<'b> 
+0

谢谢!它在对测试代码进行相同的修改后编译,我开始明白为什么存在这个问题。然而,真实情况是'transform()'是一个作为第三方库(实际上是hyper :: client :: Client :: get())提供的函数。我仍然想知道为什么'transform_and_arm(self)'不能工作。由于魔鬼一直存在到C行,因此Foo消耗在行C之后,它不会超过支撑或Foo ... –

+0

另一个相关的观察是,取消注释'devil.slay_the_world();'不会导致编译错误,但取消注释'devil.arm(buz);'然后会。我只想在'transform_and_arm(self)'中使用Foo的所有字段。 –