4
在我正在處理的事情中,我有一個「數據存儲」對象和一組可用於該數據存儲的操作。我希望能夠輕鬆擴展這組操作並創建數據存儲的備用實現。受modifier crate的啓發,我嘗試採取它的方法,主要是爲抽象(存儲,操作)對創建一個特徵,然後爲每個具體對實現它。Rust中的動態調度
不幸的是,我不能完全弄清楚如何將每個具體對實現與抽象設置綁定。這裏是一個「最小」版本的我想要做的事:
use std::fmt::Debug;
trait Target: Debug {}
impl<T: Target + ?Sized> Target for Box<T> {}
trait Weapon: Debug {}
impl<W: Weapon + ?Sized> Weapon for Box<W> {}
trait AttackStrategy<T: Target> {
fn attack(&self, &T);
}
impl<T: Target, S: AttackStrategy<T> + ?Sized> AttackStrategy<T> for Box<S> {
fn attack(&self, enemy: &T) {
&self.attack(enemy);
}
}
trait Attack {
fn attack_with<S: AttackStrategy<Self>>(&self, strategy: &S) where Self: Target + Sized {
strategy.attack(self);
}
}
impl<T: Target> Attack for T {}
#[derive(Debug)]
struct Zombie(i32);
impl Target for Zombie {}
#[derive(Debug)]
struct Bunny(i32);
impl Target for Bunny {}
#[derive(Debug)]
struct BaseballBat(i32);
impl Weapon for BaseballBat {}
#[derive(Debug)]
struct Knife(i32);
impl Weapon for Knife {}
impl AttackStrategy<Zombie> for BaseballBat {
fn attack(&self, zed: &Zombie) {
println!("Attacking {:?} with {:?}! Whack whack whack! Whew. That was close!", zed, self);
}
}
impl AttackStrategy<Bunny> for BaseballBat {
fn attack(&self, hopper: &Bunny) {
println!("Attacking {:?} with {:?}! Swoosh swoosh swoosh! Dang, he got away!", hopper, self);
}
}
impl AttackStrategy<Zombie> for Knife {
fn attack(&self, zed: &Zombie) {
println!("Attacking {:?} with {:?}! Stick stick stick! Oh no! He bit me!", zed, self);
}
}
impl AttackStrategy<Bunny> for Knife {
fn attack(&self, hopper: &Bunny) {
println!("Attacking {:?} with {:?}! Stick stick stick! Yum! Dinner!", hopper, self);
}
}
#[allow(dead_code)]
fn main() {
let louisville_slugger = BaseballBat(5);
let rabbit = Bunny(-1);
rabbit.attack_with(&louisville_slugger);
let cleaver: Box<Weapon> = Box::new(Knife(2));
let brains_seeker = Zombie(17);
brains_seeker.attack_with(&cleaver);
}
這失敗,出現錯誤:
test.rs:75:19: 75:40 error: the trait `AttackStrategy<Zombie>` is not implemented for the type `Weapon` [E0277]
test.rs:75 brains_seeker.attack_with(&cleaver);
^~~~~~~~~~~~~~~~~~~~~
有人能提出一個更好的方式來做到這一點,還是有辦法解決這個錯誤?