如何指定方法参数实现特征并且是特定类型?
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.
}
}
我不想让图书馆知道或关心 velocity
或 avg_vel
。
有没有办法编写此代码,以便我可以从 impl Environment for Env
的 update
方法内部访问 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 的建议!)
我有一个实现两个特征的库:
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.
}
}
我不想让图书馆知道或关心 velocity
或 avg_vel
。
有没有办法编写此代码,以便我可以从 impl Environment for Env
的 update
方法内部访问 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 的建议!)