[英]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 。
我怎样才能做到这一点(或以更惯用的方式实现)?
#![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.