Initialize trait-bounded structs

I am trying to simplify new function of my generic struct. Right now, I can create a new struct by using

let data: Vec<u8> = Vec::new();
ColumnIterator::new(
        data.as_slice(),
        7,
        data.as_slice().iter().step_by(7)
    );
struct ColumnIterator<'a, T: Iterator<Item = &'a u8>> {
    data: &'a [u8],
    col: usize,
    internal: T,
}

impl<'a, T: Iterator<Item = &'a u8>> ColumnIterator<'a, T> {
    fn new(data: &'a [u8], col: usize, internal: T) -> Self {
        ColumnIterator {
            data,
            col,
            internal,
        }
    }
}

However, since ColumnIterator has all information to create the internal, and for better API, I was trying to do this:

fn new(data: &'a [u8], col: usize) -> Self {
        ColumnIterator {
            data,
            col,
            internal: data.iter().step_by(col)
        }
    }
}

which gives me expected type parameter, found struct std::iter::StepBy error

How do I construct a concrete type to initialize a generic field of an struct?
Link to Playground

Inside the impl, Self refers to the (universally quantified) generic type. It does not refer to the one particular instantiation which is deduced from the return type of step_by(). Think of it like this: in this case, type inference can't go "from the inside out", i.e. you can't infer the whole generic from one method. Well, technically you could but it wouldn't make sense to use a generic in that case, because as soon as you assert that your internal field is a StepBy, you end up with a specific instantiation of your generic. The point is: if you want to use the type with a StepBy, and this leaks to the public interface, then you have to supply that type information somewhere. You can't just say that "for any type T, this will work with a StepBy", because, well, it doesn't. It only works when your T is StepBy.

I think in this case you should remove the generic altogether and simply type the internal field as StepBy<slice::Iter<&'a u8>>.

3 Likes