2016-12-05 31 views
4

我屏住了壽命和結構的世界包含可變結構:方法不與令人困惑的錯誤消息特質兼容

enum Resources { 
    Food, 
    Wood, 
    Tools, 
    Ore, 
    Metal, 
} 

struct ResourceEntry { 
    resource: Resources, 
    amount: i32, 
} 

impl ResourceEntry { 
    fn new(resource: Resources, amount: i32) -> ResourceEntry { 
     ResourceEntry { 
      resource: resource, 
      amount: amount, 
     } 
    } 
} 

trait Agent { 
    fn new<'a>(&'a mut Vec<ResourceEntry>) -> Self; 
} 

struct Miner<'a> { 
    inventory: &'a mut Vec<ResourceEntry>, 
} 

impl<'a> Agent for Miner<'a> { 
    fn new(starting_resource: &'a mut Vec<ResourceEntry>) -> Miner { 
     Miner { inventory: starting_resource } 
    } 
} 

fn main() { 
    let mut resource = ResourceEntry::new(Resources::Food, 3); 
    let mut vec = vec![resource]; 
    let miner: Miner = Miner::new(vec); 

    miner.perform(); 
} 

我收到以下錯誤

error[E0308]: method not compatible with trait 
    --> other.rs:47:5 
    | 
47 |  fn new(starting_resource: &'a mut Vec<ResourceEntry>) -> Miner 
    | ^lifetime mismatch 
    | 
    = note: expected type `fn(&'a mut std::vec::Vec<ResourceEntry>) -> Miner<'a>` 
    = note: found type `fn(&'a mut std::vec::Vec<ResourceEntry>) -> Miner<'a>` 
note: the lifetime 'a as defined on the block at 48:4... 
    --> other.rs:48:5 
    | 
48 |  { 
    | ^
note: ...does not necessarily outlive the lifetime 'a as defined on the block at 48:4 
    --> other.rs:48:5 
    | 
48 |  { 
    | ^
help: consider using an explicit lifetime parameter as shown: fn new(starting_resource: &'a mut Vec<ResourceEntry>) -> Miner 
    --> other.rs:47:5 
    | 
47 |  fn new(starting_resource: &'a mut Vec<ResourceEntry>) -> Miner 
    | ^

我不能因爲我的生活圍繞着編譯器告訴我的東西。錯誤信息說明我正在做什麼。也許我是誤解,但是這是說a的使用期限與a的使用期限不符?我認爲我對借用和所有權有很好的把握,但使用明確的生命週期和引用其他對象的對象讓我感到困惑。

是問題

fn new<'a>(&'a mut Vec) -> Self;

我曾與獲得新的正確接受了一輩子的麻煩,我想知道,如果這不是你應該做鏽?

回答

6

這是一個非常糟糕的錯誤消息,我鼓勵你to report it。如果你改變你的一生通用參數名稱...

trait Agent { 
    fn new<'a>(&'a mut Vec<ResourceEntry>) -> Self; 
} 

struct Miner<'b> { 
    inventory: &'b mut Vec<ResourceEntry>, 
} 

impl<'c> Agent for Miner<'c> { 
    fn new(starting_resource: &'c mut Vec<ResourceEntry>) -> Miner { 
     Miner { inventory: starting_resource } 
    } 
} 

你得到一個更好的錯誤:

error[E0308]: method not compatible with trait 
    --> src/main.rs:32:5 
    | 
32 |  fn new(starting_resource: &'c mut Vec<ResourceEntry>) -> Miner { 
    | ^lifetime mismatch 
    | 
    = note: expected type `fn(&'a mut std::vec::Vec<ResourceEntry>) -> Miner<'c>` 
    = note: found type `fn(&'c mut std::vec::Vec<ResourceEntry>) -> Miner<'c>` 

添加一輩子的impl不是簡寫爲在每個指定一生功能;他們有不同的範圍。你可以看到你正在嘗試做沒有意義:

fn new<'a>(&'a mut Vec<ResourceEntry>) -> Self; 

這一輩子不輸出中使用任何地方。相反,你需要做的壽命的特質發揮作用:的

trait Agent<'a> { 
    fn new(&'a mut Vec<ResourceEntry>) -> Self; 
} 

impl<'c> Agent<'c> for Miner<'c> { 
    fn new(starting_resource: &'c mut Vec<ResourceEntry>) -> Miner<'c> { 
     Miner { inventory: starting_resource } 
    } 
} 

Just so I know exactly what happened, the implementation of Agent for Miner wasn't compatible because the trait Agent didn't have a lifetime associated with it. So when it was trying to compile new in the implementation, it found that it had a lifetime from the Agent::new but a was a random other lifetime it couldn't figure out since that lifetime wasn't in the output.

類。這是不兼容的,因爲new的實施沒有生命週期參數(fn new<'x>)而特徵定義。爲new添加生命期會「解決」該問題,但不會編譯或不做你想做的事。

The lifetime at the trait level allows you to associated the lifetime in the impl block

特質水平的生命期意味着實現特質的類型可以用生命期來參數化。特質也將知道這一生。

and your able to say that the agent will have the same lifetime as the miner?

我認爲你理解這個概念,但我會指出這個術語是微妙的錯誤。 Miner將提供參考 具體的生命期;這是不是Miner的一生一樣! AgentMiner的實施將能夠使用提供的生命週期,但Agent本身並沒有一生;這只是一個特質。

這是人類的弱點,我們如何談論事物的快速和鬆散。一個值的生命週期直到它被移動時纔會生效。在Rust中,'a是生命週期註釋/通用生命週期參數,並且這些允許值包含引用。具體的生命週期將在參考值構造時替換參數。

+0

太棒了!就是這樣。我會確保報告錯誤。 正因爲如此,我確切知道發生了什麼事情,Miner Agent的實現不兼容,因爲特質Agent沒有與它關聯的生命週期。所以當它試圖在實現中編譯new時,它發現它有來自Agent :: new的生命週期,但是它是一個隨機的其他生命週期,因爲該生命週期不在輸出中,所以它無法計算出來。特質水平的生命週期允許您將impl塊中的生命週期與您的礦工生命週期相提並論。 – Erik

+1

@Erik更新了更多文字。 – Shepmaster