2016-05-16 2 views
2

Je rencontre des difficultés pour en savoir plus sur les types associés. Mon code de problème:Implémentation d'un trait qui a des types de trait associés

trait Fooer { 
    fn foo(&self); 
} 

trait FooStore { 
    type T: Fooer; 
    fn store_foo(&self, fooer: Self::T); 
} 

#[allow(dead_code)] 
struct DB {} 

impl FooStore for DB { 
    type T = Fooer; 

    fn store_foo(&self, _fooer: Self::T) {} 
} 

fn main() {} 

Play link

L'objectif ici est d'utiliser des types associés pour faire le trait FooStore pas besoin de la syntaxe maladroite et problématique de impl<F:Fooer, T: FooStore<F>> FooStore<F> for DB parce que souvent F se plaint pas utilisé.

Cependant, le official docs sur cette fonctionnalité montre les objets implémentant le type associé sous-jacent - mais pas les traits. Dans cet exemple, DB ne sait pas quelles structures peuvent être passées en store_foo(..), il doit donc utiliser un trait pour résoudre ce problème. Cela dit, comment puis-je obtenir un type associé pour utiliser un trait au cours de impl? C'est, comment puis-je écrire type T = Fooer;? Ou est-ce que j'utilise ce mauvais en quelque sorte?

Note: J'ai quelques problèmes pour construire cet exemple, j'essaye de le corriger maintenant. L'erreur que je faisais est:

cargo: the trait `Fooer` cannot be made into an object [E0038] 

Répondre

3

Le but ici est d'utiliser des types associés pour faire le trait FooStore pas besoin de la syntaxe maladroite et problématique de impl<F:Fooer, T: FooStore<F>> FooStore<F> for DB parce que souvent F se plaint pas utilisé.

Votre struct DB a besoin d'assigner un type concret qui implémente Fooer-FooStore::T. Fooer est un trait, mais peut également être utilisé comme un type non-dimensionné. Cependant, vous ne pouvez pas utiliser ici un type non dimensionné, car vous ne pouvez pas passer un argument d'un type non dimensionné par valeur (ce qui est requis par FooStore::store_foo). Si vous ne souhaitez pas que DB affecte un type particulier à FooStore::T, vous pouvez définir DB comme générique.

use std::marker::PhantomData; 

#[allow(dead_code)] 
struct DB<F: Fooer> { 
    _phantom: PhantomData<F>, 
} 

impl<F: Fooer> FooStore for DB<F> { 
    type T = F; 

    fn store_foo(&self, _fooer: Self::T) {} 
} 

Notez l'utilisation de PhantomData: nous l'utilisons pour forcer le paramètre T à utiliser, et il indique également que DB<T> possède conceptuellement objets de type T.