【问题标题】:Parameter type may not live long enough参数类型的寿命可能不够长
【发布时间】:2015-09-17 08:20:12
【问题描述】:

我有一个简单的程序,我正在尝试实现多态帐户类型:

enum AccountType {
    INVALID,
    TYPE1,
    TYPE2,
}

trait Account {
    fn get_name(&self) -> String;
    fn get_type(&self) -> AccountType;
}

struct Accounts {
    accounts: Vec<Box<Account>>,
}

impl Accounts {
    fn new() -> Accounts {
        let accs: Vec<Box<Account>> = Vec::new();
        Accounts { accounts: accs }
    }

    fn add_account<A: Account>(&self, account: A) {
        self.accounts.push(Box::new(account));
    }
}

fn main() {
    let accounts = Accounts::new();
}

(Rust Playground)

当我编译它时,我看到以下错误:

error[E0310]: the parameter type `A` may not live long enough
  --> src/main.rs:23:28
   |
22 |     fn add_account<A: Account>(&self, account: A) {
   |                    -- help: consider adding an explicit lifetime bound `A: 'static`...
23 |         self.accounts.push(Box::new(account));
   |                            ^^^^^^^^^^^^^^^^^
   |
note: ...so that the type `A` will meet its required lifetime bounds
  --> src/main.rs:23:28
   |
23 |         self.accounts.push(Box::new(account));
   |                            ^^^^^^^^^^^^^^^^^

我尝试为类型添加生命周期,但找不到正确的方法。如果这不是在 Rust 中进行多态性的正确方法,请告诉我。

【问题讨论】:

    标签: rust


    【解决方案1】:

    我将尝试给出更彻底的答案:这个问题与Accountsaccounts 成员的定义有关。 Vec&lt;Box&lt;Account&gt;&gt; 在此上下文中等同于 Vec&lt;Box&lt;Account + 'static&gt;&gt;,即该框不能包含对堆栈上数据的任何引用。另一方面,add_account 的声明并不限制类型的生命周期:它等同于 fn add_account&lt;'a, A: Account + 'a&gt;(&amp;self, account: A) {

    解决方案是确保类型 A 的寿命足够长。最简单的方法是添加错误消息中建议的A: 'static 绑定 (fn add_account&lt;A: Account + 'static&gt;(&amp;self, account: A) {)。

    如果你不想复制账户数据,你可以做一些更复杂的事情,像这样:

    struct Accounts<'a> {
        accounts: Vec<&'a Account + 'a>
    }
    
    impl<'a> Accounts<'a> {
        fn new() -> Accounts<'a> {
            Accounts { accounts: Vec::new() }
        }
    
        fn add_account<A: Account + 'a>(&mut self, account: &'a A) {
            self.accounts.push(Box::new(account));
        }
    }
    

    不过,此时,您的数据结构可能比您实际需要的更通用。

    【讨论】:

    • 您能否详细说明Vec&lt;Box&lt;Account&gt;&gt; in this context is equivalent to Vec&lt;Box&lt;Account + 'static&gt;&gt; 的含义?我的意思是,上面代码中的什么表明它相当于Vec&lt;Box&lt;Account + 'static&gt;&gt;
    • 每个特征对象都有一个关联的生命周期;如果您没有指定生命周期,编译器会使用一些简单的规则来推断它。 doc.rust-lang.org/book/second-edition/… 有一般描述; github.com/rust-lang/rfcs/blob/… 有理由。
    【解决方案2】:

    编译器的建议确实有效。如果你写add_account如下:

    fn add_account<A: Account + 'static>(&mut self, account: A) {
        self.accounts.push(Box::new(account));
    }
    

    您的代码已编译。 (顺便说一下,这里需要&amp;mut self,而不是&amp;self

    【讨论】:

    • 可能值得解释为什么会发生错误以及为什么修改后的代码可以修复它。
    • 谢谢。在这种情况下,生命周期是否必须为static
    • @russoue 是的。这个界限的重点是不能允许 trait 对象比它引用的任何东西都活得更久。 'static 绑定意味着对象不能有任何非静态引用。
    • @russoue 我实际上不确定。可以通过向Accounts 添加生命周期参数来实现。我在这里有点超出我的深度,而且我不在电脑附近,所以我现在无法进行实验。我稍后会玩弄它,如果我发现了会告诉你的。
    • 'static 并不意味着“对象与程序一样长”。在 trait bounds 'static (或任何其他生命周期边界)中意味着该类型不能包含生命周期短于指定生命周期的引用。请注意,absence 引用也符合条件 - 因此,其中不包含引用的每个类型(或者换句话说,没有任何类型参数)都满足任何生命周期限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 2017-03-09
    • 1970-01-01
    • 2015-06-26
    • 2015-05-26
    相关资源
    最近更新 更多