según prentice philip octava méxico mercadotecnia marketing libro kotler hall gratis gary fundamentos educación edición edicion armstrong 8va rust traits

rust - prentice - Implementé un rasgo para otro rasgo pero no puedo llamar a métodos de ambos rasgos



marketing 8va edicion (2)

Debe implementar el segundo rasgo para los objetos que implementan el primer rasgo :

impl<T> Sleep for T where T: HasBed, { fn sleep(&self) { self.sleep_in_bed() } }

Anteriormente, estaba implementando Sleep para el tipo de rasgo, mejor expresado como dyn HasBed . Consulte ¿Qué significa "dyn" en un tipo? para más detalles.

Sin embargo, esto se interrumpirá tan pronto como agregue una segunda implementación general:

impl<T> Sleep for T where T: HasTent, { fn sleep(&self) { self.sleep_in_tent() } }

Con

error[E0119]: conflicting implementations of trait `Sleep`: --> src/main.rs:24:1 | 10 | / impl<T> Sleep for T 11 | | where 12 | | T: HasBed, 13 | | { ... | 16 | | } 17 | | } | |_- first implementation here ... 24 | / impl<T> Sleep for T 25 | | where 26 | | T: HasTent, 27 | | { ... | 30 | | } 31 | | } | |_^ conflicting implementation

Es posible que algo implemente tanto HasBed como HasTent . Si apareciera algo que implementara ambos, entonces el código ahora sería ambiguo. La solución para esto sería la especialización , pero aún no hay una implementación estable de eso.

¿Cómo logras tu objetivo? Creo que ya ha sugerido la mejor solución actual: escribir una macro. También podría escribir su propia macro derivada . Las macros realmente no son tan malas, pero pueden ser difíciles de escribir.

Otra cosa, que puede basarse completamente en los nombres que eligió para su ejemplo, sería simplemente integrar estructuras en otras estructuras, opcionalmente haciéndolas públicas. Dado que su implementación de Sleep básicamente solo depende de la cama / tienda de campaña, no se perderá ninguna funcionalidad al hacer esto. Por supuesto, algunas personas pueden sentir que eso rompe la encapsulación. Puede volver a crear macros para implementar una especie de delegación.

trait Sleep { fn sleep(&self); } struct Bed; impl Bed { fn jump(&self) {} } impl Sleep for Bed { fn sleep(&self) {} } struct Tent; impl Tent { fn hide(&self) {} } impl Sleep for Tent { fn sleep(&self) {} } struct Jim { bed: Bed, } struct Jane { tent: Tent, } fn main() { let jim = Jim { bed: Bed }; jim.bed.sleep(); }

Tengo un rasgo llamado Sleep :

pub trait Sleep { fn sleep(&self); }

Podría proporcionar una implementación diferente del sueño para cada estructura, pero resulta que la mayoría de las personas duerme de muy pocas maneras. Puedes dormir en una cama:

pub trait HasBed { fn sleep_in_bed(&self); fn jump_on_bed(&self); } impl Sleep for HasBed { fn sleep(&self) { self.sleep_in_bed() } }

Si estás acampando, puedes dormir en una tienda de campaña:

pub trait HasTent { fn sleep_in_tent(&self); fn hide_in_tent(&self); } impl Sleep for HasTent { fn sleep(&self) { self.sleep_in_tent() } }

Hay algunos casos extraños. Tengo un amigo que puede dormir parado contra una pared, pero la mayoría de las personas, la mayoría de las veces, caen en un caso simple.

Definimos algunas estructuras y las dejamos dormir:

struct Jim; impl HasBed for Jim { fn sleep_in_bed(&self) {} fn jump_on_bed(&self) {} } struct Jane; impl HasTent for Jane { fn sleep_in_tent(&self) {} fn hide_in_tent(&self) {} } fn main() { use Sleep; let jim = Jim; jim.sleep(); let jane = Jane; jane.sleep(); }

¡UH oh! Error de compilación:

error[E0599]: no method named `sleep` found for type `Jim` in the current scope --> src/main.rs:44:9 | 27 | struct Jim; | ----------- method `sleep` not found for this ... 44 | jim.sleep(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `sleep`, perhaps you need to implement it: candidate #1: `Sleep` error[E0599]: no method named `sleep` found for type `Jane` in the current scope --> src/main.rs:47:10 | 34 | struct Jane; | ------------ method `sleep` not found for this ... 47 | jane.sleep(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `sleep`, perhaps you need to implement it: candidate #1: `Sleep`

Este error del compilador es extraño porque si había algo mal con un rasgo que implementaba otro rasgo, esperaba escucharlo cuando lo hice, no en la parte inferior del programa cuando trato de usar el resultado.

En este ejemplo, solo hay 2 estructuras y 2 formas de dormir, pero en el caso general hay muchas estructuras y varias formas de dormir (pero no tantas formas como estructuras).

Una Bed es principalmente una implementación para Sleep , pero en el caso general una Bed tiene muchos usos y podría implementar muchas cosas.

El único enfoque inmediatamente obvio es convertir el impl Sleep for... en una macro que las estructuras usan, pero eso parece extraño y terrible.


Podemos usar elementos asociados aquí.

pub trait Sleep: Sized { type Env: SleepEnv; fn sleep(&self, env: &Self::Env) { env.do_sleep(self); } fn get_name(&self) -> &''static str; } pub trait SleepEnv { fn do_sleep<T: Sleep>(&self, &T); }

Luego, implementamos dos entornos de sueño diferentes.

struct Bed; struct Tent; impl SleepEnv for Bed { fn do_sleep<T: Sleep>(&self, person: &T) { println!("{} is sleeping in bed", person.get_name()); } } impl SleepEnv for Tent { fn do_sleep<T: Sleep>(&self, person: &T) { println!("{} is sleeping in tent", person.get_name()); } }

La última pieza son las implementaciones concretas de ellos.

struct Jim; struct Jane; impl Sleep for Jim { type Env = Bed; fn get_name(&self) -> &''static str { "Jim" } } impl Sleep for Jane { type Env = Tent; fn get_name(&self) -> &''static str { "Jane" } }

Código de prueba:

fn main() { let bed = Bed; let tent = Tent; let jim = Jim; let jane = Jane; jim.sleep(&bed); jane.sleep(&tent); }