2017-08-26 39 views
1

的熬濃的問題如下所示:使用通用特質S1上<T>強制我個人有T活得比小號

use std::marker::PhantomData; 

struct WorldState<'a> { 
    state: &'a f64, 
} 

trait CalculateWorldState<T> { 
    fn state_value(&mut self, input: &T) -> f64; 
} 


trait LearningAlgorithm<T> { 
    fn print_learning_information(&self, &T); 
} 

struct EvolutionaryAlgorithm<F, T> 
where 
    F: CalculateWorldState<T>, 
{ 
    //I need this since I only use T as a method parameter, I do not save it anywhere 
    //T are different ways to represent the current worldstate and are 
    //short-lived (new ones generated every frame) 
    _p_: PhantomData<T>, 
    //I don't actually need this one in the real example since I have 
    //an instatiated version of type CalculateWorldState saved in the 
    //struct but I use phantomdata for simplicity of the example 
    _p: PhantomData<F>, 
} 

impl<F, T> LearningAlgorithm<T> for EvolutionaryAlgorithm<F, T> 
where 
    F: CalculateWorldState<T>, 
{ 
    fn print_learning_information(&self, input: &T) { 
     println!("My learning goes splendid!"); 
     //do something with &T by calling the object of type 
     //CalculateWorldState which we have saved somewhere, but do 
     //not save the &T reference anywhere, just look at it 
    } 
} 

struct WorldIsInGoodState {} 

impl<'a> CalculateWorldState<WorldState<'a>> for WorldIsInGoodState { 
    fn state_value(&mut self, input: &WorldState) -> f64 { 
     100. 
    } 
} 

fn main() { 
    let mut a: Box<LearningAlgorithm<WorldState>> = 
     Box::new(EvolutionaryAlgorithm::<WorldIsInGoodState, WorldState> { 
      _p: PhantomData, 
      _p_: PhantomData, 
     }); 
    { 
     let state = WorldState { state: &5. }; 
     a.print_learning_information(&state); 
    } 
} 

Playground

以上代碼編譯失敗:

error[E0597]: borrowed value does not live long enough 
    --> src/main.rs:59:5 
    | 
57 |   let state = WorldState { state: &5. }; 
    |           -- temporary value created here 
58 |   a.print_learning_information(&state); 
59 |  } 
    | ^temporary value dropped here while still borrowed 
60 | } 
    | - temporary value needs to live until here 

WorldState<'a>是一個很短暫的數據類型(每幀一個),而LearningAlgorithm是一個很長的壽命的數據類型(多個遊戲)。但是,我實施這件事的方式,Rust渴望相信,我傳遞給print_learning_information的每個WorldState必須比LearningAlgorithm長。

我做錯了什麼?這怎麼能被處理?

有幾件事情我不喜歡做的事:

  • WorldState含有正常狀態(因爲實際上它包含了一些載體,而不是一個f64,我不想周圍將它們複製到WorldState當通過每個球員自己的世界觀)結構
  • 只要退出這個項目,並開始一個新的(你們都知道,投入一些時間後,你不想把所有的工作都扔掉)
+0

該問題似乎是暫時的。爲什麼不在第60行結束的範圍內定義var?像'let wstate = 5;''你的真實狀態更復雜,所以可能已經在那裏了。 – hutch

+0

問題是,內部範圍實際上是遊戲循環。我可能會把馬格德的狀態變成我的遊戲對象的一個​​變量,這樣它就可以在整個遊戲中生存下來,我只需要改變它。但是學習算法甚至可以通過多種遊戲存活下來,並且我無法通過所有遊戲使遊戲狀態變爲全局變量,因爲生存這麼長時間的唯一對象是學習算法,遊戲對象是爲每個遊戲新創建的 – kave

+0

您的示例在每晚的Rust中工作。我不確定哪些更改可以編譯。 – red75prime

回答

0

您的問題可以歸結爲

struct WorldState<'a> { 
    state: &'a f64, 
} 

trait LearningAlgorithm<T> { 
    fn print_learning_information(&self, &T); 
} 

struct EvolutionaryAlgorithm(); 

impl<T> LearningAlgorithm<T> for EvolutionaryAlgorithm 
{ 
    fn print_learning_information(&self, input: &T) { 
    } 
} 

fn main() { 
    // scope a 
    let mut a: Box<LearningAlgorithm<WorldState>> = 
     Box::new(EvolutionaryAlgorithm()); 
    { // scope b 
     let val = 5.; 
     let state = WorldState { state: &val }; 
     a.print_learning_information(&state); 
    } 
} 

注意WorldState是一類的構造函數,而不是一個具體類型。 Lifetime elision允許您編寫Box<LearningAlgorithm<WorldState>>,但沒有爲WorldState明確指定生命週期參數,但這僅表示編譯器選擇了一些適當的生命週期參數。

在此情況下,爲WorldState選擇的生存期爲scope a,因此a的類型爲Box<LearningAlgorithm<WorldState<'scope_a>>>。因此,state應該有WorldState<'scope_a>類型,並且它包含的引用應該對scope a有效,但該引用指向的值僅存在於scope b中。

您需要支持更高版本的類型才能使您的示例按原樣運行,但Rust不提供此類示例。

最簡單的解決方案是通過替換參考Rc來擺脫WorldState的使用壽命參數。也許有人會想出更好的解決方案。

相關問題