簡體   English   中英

處理`Into`泛型時的Rust壽命問題

[英]Rust lifetime issue when dealing with `Into` generics

感謝您糾正我的提問方式。 我進行了幾次修訂,使代碼可編譯。

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()方法旨在通過buz bracebuz來使用Foo的實例。 它調用brace.transform()使brace成為Devil 它通過為惡魔提供buz.unwrap()增強惡魔。

問題是,調用let weapon = buz.into(); 是合法的,同時調用devil = devil.arm(buz); 導致終身問題。

看來問題與壽命有關。 如果沒有魔鬼的“ a”,那么所有這些問題都將消失。

編輯我以前的答案不能很好地解釋問題。 這是另一種嘗試。

您有此問題,因為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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM