如何指定方法参数实现特征并且是特定类型?

How to specify that a method argument implements a trait and is a specific type?

我有一个实现两个特征的库:


pub trait Creature {
    // fn get_name(&self) -> &str;
    // etc
}

pub trait Environment {
    fn update(&mut self, creature:&impl Creature);
}

pub struct World <E:Environment, T:Creature> {
    pub environs: E,
    pub creatures: Vec<T>,
}

impl <E:Environment, T:Creature> World<E, T> {
    pub fn update(&mut self) {
        for creature in self.creatures.iter() {
            self.environs.update( creature );
        }
    }
}

我想像这样使用我的图书馆:

use my_library::{Environment, Creature, World};
struct Dog {
    velocity: f32,
}

impl Creature for Dog {}

struct Env {
    avg_vel: f32,
}

impl Environment for Env {
    fn update(&mut self, dog: &impl Creature) {
        self.avg_vel = 0.; // want to access dog.velocity here. 
    }
}

我不想让图书馆知道或关心 velocityavg_vel

有没有办法编写此代码,以便我可以从 impl Environment for Envupdate 方法内部访问 Dog 的内部结构?

换句话说,我想将 world.creatures 对象的具体类型与 world.environs.method 参数接收的类型相结合。

从计算安全的角度来看,这似乎应该是可能的。

问题是您定义了一个具有 update 方法的特征,您可以向该方法传递任何 Creature;至少你的特质是这样说的。

当您在 World 上实现该特征时,您说只有 &Dog 可以用作此处的参数。

在你的情况下,是的,每只狗都是 Creature,但并非每只 Creature 都是 Dog。你在那里有相互矛盾的要求。您的实现应该符合您的特点。

具有相关特征

my_library: (rust 版本 1.56.1)

pub trait Creature {
    // fn get_name(&self) -> &str;
    // etc
}

pub trait Environment {
    type CCT; // Concrete Creature Type
    fn update(&mut self, creature:&Self::CCT);
}

pub struct World <'a, E:Environment, T:Creature> {
    pub environs: &'a mut E,
    pub creatures: Vec<T>,
}

impl <'a, E:Environment<CCT = T>, T:Creature> World<'a, E, T> {
    pub fn new(env: &'a mut E) -> Self {
        Self { 
            environs: env, 
            creatures: Vec::new(), 
        }
    }

    pub fn update(&mut self) {
        for creature in self.creatures.iter() {
            self.environs.update( creature );
        }
    }
}

注意,<CCT = T> 在 impl 世界中。它说,“嘿,你的环境将使用特定类型的生物来实例化世界。”

及相关用法:

use my_library::{Environment, Creature, World};
struct Dog {
    velocity: f32,
}

impl Creature for Dog {}

struct Env {
    avg_vel: f32,
}

impl Environment for Env {
    type CCT = Dog;
    fn update(&mut self, dog: &self::CCT) {
        self.avg_vel = dog.velocity; // Yay, we have a dog!
    }
}

fn main() { 
    let mut env = Env { avg_vel: 0. };
    let mut world :World<Env, Canvas> = World::new( &mut env );
    world.environs.avg_vel = 5.; // And we can still do this too!
    ...

可能还有其他不使用关联特征的解决方案,但这暂时有效。

(感谢 Rob Napier 的建议!)