5

As an excuse to learn Rust, I'm working on code for genetic algorithms, and genetic programming later.

I declared a trait for mutation operations:

pub trait Mutator<IndvidualType> {
    fn mutate(&self, individual: &IndvidualType) -> IndvidualType;
}

It is easy to implement the trait for every single IndividualType, but I want something more general, a trait which is common for every list (vector) type genome, something like:

pub trait HasVectorGenome<IndividualType, BaseType>  {
    fn new_from_vec(genome: Vec<BaseType>) -> IndvidualType;
    fn get_vec(&self) -> Vec<BaseType>;
}

I want to have a generic mutator which is able to mutate every HasVectorGenome whose BaseType implements Rand (in order to be able to generate a new random value). Something like:

struct GeneralMutator;

impl<B, T> Mutator<T> for GeneralMutator
    where T: HasVectorGenome<T, B>,
          B: Rand
{
    fn mutate(&self, individual: &T) -> T {
        let genome: Vec<B> = individual.get_vec();
        genome[0] = rand::random::<B>();
        T::new_from_vec(genome)
    }
}

I've got the error the type parameter `B` is not constrained by the impl trait, self type, or predicates, and I can't compile. I do not know how to express this correctly.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
KilyenOrs
  • 1,456
  • 1
  • 20
  • 26
  • Likely duplicate of https://stackoverflow.com/q/30440474/155423 or https://stackoverflow.com/q/31809355/155423 – Shepmaster Feb 20 '16 at 16:15

1 Answers1

4

I've put a complete working version of this code on the playground (except that I stubbed out the random parts).

First, I removed the IndividualType parameter from HasVectorGenome. This is simply the type for which the trait is implemented, and your definition of the trait is inconsistent about this (new_from_vec returns IndividualType but get_vec consumes Self).

Second, I made BaseType an associated type, meaning that there is a single unique base type for any individual type. This is technically a restriction, but in most circumstances you don't need the flexibility and it makes the types simpler (and is in fact the primary change needed to get rid of the error you're seeing). So the trait is now:

pub trait HasVectorGenome  {
    type BaseType;
    fn new_from_vec(genome: Vec<Self::BaseType>) -> Self;
    fn get_vec(&self) -> Vec<Self::BaseType>;
}

Then, I adjusted the where clause of the GeneralMutator implementation:

impl<T> Mutator<T> for GeneralMutator
  where T: HasVectorGenome,
        T::BaseType : Rand
  • Do you think this question is a duplicate of http://stackoverflow.com/q/30440474/155423 or http://stackoverflow.com/q/31809355/155423? – Shepmaster Feb 20 '16 at 16:13
  • @Shepmaster Eh, sorta, maybe? It falls in the same general pattern of replacing trait type parameters with associated types, and the same error message crops up in the second link, but the answers are quite different (and would still be different if I went into the *why* instead of just giving code). –  Feb 20 '16 at 16:24
  • Thank you for your time, it is the perfect answer! – KilyenOrs Feb 20 '16 at 16:29