Parameter type may not live long enough

2019-02-19 00:25发布

I have a simple program where I am trying to implement a polymorphic account type:

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)

When I compile it, I see the following error:

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));
   |                            ^^^^^^^^^^^^^^^^^

I have tried adding lifetimes to the type but could not find the right way to do it. Please let me know if this is not the right way to do polymorphism in Rust.

标签: rust
2条回答
兄弟一词,经得起流年.
2楼-- · 2019-02-19 01:01

I'll try to give a more thorough answer: the issue has to do with the definition of the accounts member of Accounts. Vec<Box<Account>> in this context is equivalent to Vec<Box<Account + 'static>>, i.e. the box can't contain any references to data on the stack. On the other hand, the declaration of add_account doesn't restrict the lifetime of the type: it's equivalent to fn add_account<'a, A: Account + 'a>(&self, account: A) {.

The solution is to make sure the type A lives long enough. The simplest approach is to just add the A: 'static bound suggested in the error message (fn add_account<A: Account + 'static>(&self, account: A) {).

If you don't want to copy the Account data, you can do something more complicated, like this:

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));
    }
}

At this point, though, you have a data structure which is probably more general than you actually need.

查看更多
Lonely孤独者°
3楼-- · 2019-02-19 01:03

The compiler's suggestion actually works. If you write add_account as follows:

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

your code compiles. (Incidentally, you need &mut self, not &self here)

查看更多
登录 后发表回答