繁体   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