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.

1

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

3 Comments

Do you think this question is a duplicate of stackoverflow.com/q/30440474/155423 or stackoverflow.com/q/31809355/155423?
@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).
Thank you for your time, it is the perfect answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.