syntaxrusttype-bounds

How to write fuctions that takes IntoIter more generally


I was reading an answer to stackoverflow question and tried to modify the function history to take IntoIter where item can be anything that can be transformed into reference and has some traits Debug in this case.

If I will remove V: ?Sized from the function definition rust compiler would complain that it doesn't know the size of str at compile time.

use std::fmt::Debug;

pub fn history<I: IntoIterator, V: ?Sized>(i: I) where I::Item: AsRef<V>, V: Debug {
    for s in i {
        println!("{:?}", s.as_ref());
    }
}

fn main() {
    history::<_, str>(&["st", "t", "u"]);
}

I don't understand why compiler shows error in the first place and not sure why the program is working properly if I kind of cheat with V: ?Sized.


Solution

  • I kind of cheat with V: ?Sized

    It isn't cheating. All generic arguments are assumed to be Sized by default. This default is there because it's the most common case - without it, nearly every type parameter would have to be annotated with : Sized.

    In your case, V is only ever accessed by reference, so it doesn't need to be Sized. Relaxing the Sized constraint makes your function as general as possible, allowing it to be used with the most possible types.

    The type str is unsized, so this is not just about generalisation, you actually need to relax the default Sized constraint to be able to use your function with str.