es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo especificar que un argumento de método implemente un rasgo y sea de un tipo específico?

Tengo una biblioteca que implementa dos rasgos:


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 ); } } }

Quiero usar mi biblioteca de la siguiente manera:

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.; // quiero acceder a dog.velocity aquí. 
    }
}

No quiero que la biblioteca conozca o se preocupe por la “velocidad” o “avg_vel”.

¿Hay alguna forma de escribir este código, de modo que pueda acceder a los detalles internos de “Dog” desde el método “update” de “impl Environment for Env”?

Para reformularlo, quiero acoplar el tipo concreto de los objetos “world.creatures” con el tipo que recibe el argumento “world.environs.method”.

Parece que debería ser posible desde el punto de vista de la seguridad computacional.</e,></e:environment,></e:environment,>

Tags:  ,

Answer

  1. Avatar for davy.ai

    No, no hay una forma directa de acceder a los detalles internos de Dog desde el método update para impl Environment for Env, sin violar los límites de abstracción proporcionados por los traits. Esto se debe a que los traits están diseñados para crear una separación de responsabilidades entre las diferentes partes de un programa, permitiendo que cada parte se desarrolle y cambie de forma independiente. En particular, el trait Creature no debe exponer ninguna información sobre el estado interno o el comportamiento de sus implementaciones, como el campo velocity de Dog.

    Una opción para lograr lo que deseas sería definir un trait específico para la funcionalidad que necesitas, como VelocityProvider, e implementarlo para Dog (y cualquier otra criatura que lo necesite) por separado del trait Creature:

    pub trait VelocityProvider {
        fn get_velocity(&self) -> f32;
    }
    
    impl VelocityProvider for Dog {
        fn get_velocity(&self) -> f32 {
            self.velocity
        }
    }
    

    Luego puedes actualizar tu estructura Env para que tome un argumento &impl VelocityProvider en lugar de &impl Creature, y llamar al método get_velocity en él:

    impl Environment for Env {
        fn update(&mut self, dog: &impl VelocityProvider) {
            self.avg_vel = dog.get_velocity();
        }
    }
    

    Finalmente, puedes actualizar tu estructura World para usar VelocityProvider en lugar de Creature:

    pub struct World<e: environment,="" t:="" velocityprovider=""> {
        pub environs: E,
        pub creatures: Vec<t>,
    }
    
    impl<e: environment,="" t:="" velocityprovider=""> World<e, t=""> {
        pub fn update(&mut self) {
            for creature in self.creatures.iter() {
                self.environs.update(creature);
            }
        }
    }
    

    De esta manera, el trait Creature permanece abstracto y no expone ningún detalle interno sobre sus implementaciones, al tiempo que permite agregar funcionalidades específicas a través de traits separados.</e,>

Comments are closed.