簡體   English   中英

使用帶有生命周期參數的特征作為通用界限的問題

[英]Trouble with using a trait with lifetime parameter as a generic bound

我正在嘗試使用一個特征Context ,其不同的實現允許Cell以不同的方式訪問其所有者World ,如以下人為的示例代碼(編譯; 此處為游樂場):

struct Cell {    
    value: i32,    
} 
    
impl Cell {    
    fn evolve<'a>(&self, ctx: impl Context<'a>) -> Cell {    
        Cell {    
            value: self.value + ctx.get_rate()    
        }    
    }    
}    
    
struct World {    
    cell: Cell,    
    magic: i32,    
}    
    
impl World {    
    fn evolve_cell<'a, C: Context<'a>>(&'a self) -> Cell {    
        let ctx = C::new(self);        
        self.cell.evolve(ctx)        
    }    
        
    fn update(&mut self) {    
        self.cell = self.evolve_cell::<MagicContext>();    
    }    
}        
         
trait Context<'a> {    
    fn new(world: &'a World) -> Self;    
    fn get_rate(&self) -> i32;    
}    
     
struct MagicContext<'a> {    
    world: &'a World,        
}                            
                             
impl <'a> Context<'a> for MagicContext<'a> {                     
    fn new(world: &'a World) -> Self {    
        MagicContext {    
            world    
        }    
    }        
             
    fn get_rate(&self) -> i32 {    
        self.world.magic    
    }    
}        
         
fn main() {    
    let mut world = World {    
        cell: Cell { value: 2 },    
        magic: 3,    
    };    
          
    world.update();    
    println!("{}", world.cell.value);    
}

我不想將MagicContext指定為World::update中的Context實現,而是希望能夠在main中的調用站點選擇實現——如下所示:

impl World {    
    // ...

    fn update<C: Context>(&mut self) {    
        self.cell = self.evolve_cell::<C>();    
    }
}

// ...

fn main() {
    // ...
    world.update::<MagicContext>();
    // ...
}

但是Context需要一個生命周期參數。 我不能引入像fn update<'a, C: Context<'a>>(&mut self)這樣的生命周期參數,因為上下文的生命周期會阻止我改變self

error[E0506]: cannot assign to `self.cell` because it is borrowed
  --> lifetime.rs:25:9
   |
24 |     fn update<'a, C: Context<'a>>(&'a mut self) {
   |               -- lifetime `'a` defined here
25 |         self.cell = self.evolve_cell::<C>();
   |         ^^^^^^^^^^^^-----------------------
   |         |           |
   |         |           borrow of `self.cell` occurs here
   |         |           argument requires that `*self` is borrowed for `'a`
   |         assignment to borrowed `self.cell` occurs here

一些看似相似的問題使我按照fn update<C: for <'a> Context<'a>>(&mut self)的思路查看了 Higher-Rank Trait Bounds ,但編譯器告訴我:

error: implementation of `Context` is not general enough
  --> lifetime.rs:56:11
   |
56 |     world.update::<MagicContext>();
   |           ^^^^^^ implementation of `Context` is not general enough
   |
   = note: `Context<'0>` would have to be implemented for the type `MagicContext<'_>`, for any lifetime `'0`...
   = note: ...but `Context<'1>` is actually implemented for the type `MagicContext<'1>`, for some specific lifetime `'1`

我希望能夠完全擺脫Context的生命周期參數,但沒有它我不知道如何表達new的 function 。

我怎樣才能做到這一點(或以更慣用的方式實現)?

這可以使用GAT游樂場)解決:

#![feature(generic_associated_types)]

struct Cell {
    value: i32,
}

impl Cell {
    fn evolve(&self, ctx: impl Context) -> Cell {
        Cell {
            value: self.value + ctx.get_rate(),
        }
    }
}

struct World {
    cell: Cell,
    magic: i32,
}

impl World {
    fn evolve_cell<C: Context>(&self) -> Cell {
        let ctx = C::new(self);
        self.cell.evolve(ctx)
    }

    fn update<C: Context>(&mut self) {
        self.cell = self.evolve_cell::<C>();
    }
}

trait Context {
    type Instance<'a>: Context;
    fn new<'a>(world: &'a World) -> Self::Instance<'a>;
    fn get_rate(&self) -> i32;
}

struct MagicContext<'a> {
    world: &'a World,
}

impl<'a> Context for MagicContext<'a> {
    type Instance<'b> = MagicContext<'b>;
    
    fn new<'b>(world: &'b World) -> Self::Instance<'b> {
        MagicContext { world }
    }

    fn get_rate(&self) -> i32 {
        self.world.magic
    }
}

不幸的是,GAT 不穩定。 不過,有一個終生 GAT 的解決方法:創建另一個具有關聯類型的特征:

trait ContextInstance<'a> {
    type Instance: Context;
}
trait Context: for<'a> ContextInstance<'a> {
    fn new<'a>(world: &'a World) -> <Self as ContextInstance<'a>>::Instance;
    fn get_rate(&self) -> i32;
}

impl<'a, 'b> ContextInstance<'b> for MagicContext<'a> {
    type Instance = MagicContext<'b>;
}
impl<'a> Context for MagicContext<'a> {
    fn new<'b>(world: &'b World) -> <Self as ContextInstance<'b>>::Instance {
        MagicContext { world }
    }

    fn get_rate(&self) -> i32 {
        self.world.magic
    }
}

游樂場

暫無
暫無

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

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