简体   繁体   中英

In Rust, how to define a generic function for converting Vec<T> to Vec<U>

I need something like:

fn my_convert<T, U>(v: &Vec<U>)->Vec<T>{
    v.iter().map(|&t|t).collect()
}

Of course, I suppose that only vector of builtin numeric types could be passed to the function.

The compiler tells me that I need to give the trait FromIterator for Vec

the trait std::iter::FromIterator<U> is not implemented for `std::vec::Vec

then, I added

impl<T, U> std::iter::FromIterator<U> for Vec<T>{
    fn from_iter<I>(iter:I)->Self where I: IntoIterator<Item=U>{
        Vec::<T>::new()    // just for test
    }
}

conflicting implementations of trait std::iter::FromIterator<_> for type std::vec::Vec<_> : note: conflicting implementation in crate alloc : - impl std::iter::FromIterator for std::vec::Vec;rustc(E0119)

As we all known, in C++, this kind of conversion is straight forward and intutive. I am a beginner of Rust. I don't know how to define a function like above. I even don't known if it is could be achieved in Rust because of the complexity of the trait for generic type.

Thanks!

The Rust From trait is your general purpose "how to get from A to B". If there's a reasonable way to go from U to T , then T: From<U> will be implemented. Consider

fn my_convert<T, U>(v: Vec<U>) -> Vec<T>
where T: From<U> {
  v.into_iter().map(T::from).collect()
}

Note that I do take ownership of the v vector. the From::from function consumes its argument, so we should also consume the vector. You could write a completely general version of this function that works with arbitrary iterators, and then it'll be easier to go back and forth between iterators which own their data and those that only borrow.

fn my_convert1<T, U, I>(v: I) -> Vec<T>
where T: From<U>,
      I: Iterator<Item=U> {
  v.map(T::from).collect()
}

But at that point, you'd be better off just writing v.map(T::from).collect() directly, and any reasonably proficient Rust programmer will instantly know what you're doing.

One point to note here, since you've mentioned that you're a C++ programmer. In C++, template functions can simply be written as-is, and then, when the caller instantiates a version of it, the compiler checks whether it's okay or not. So your proposed function in the OP works fine, since the compiler only checks it when it's called. Rust (and indeed most languages with generics) isn't like that.

In Rust, on the other hand, when you write the my_convert function, Rust checks at that time that all of the types line up. You can't write a function that only works some of the time. If you say my_convert works for all T and U , then it had better work for all of them, and Rust's type checker and borrow checker are going to verify that immediately. If not, then you'd better do as I did above and restrict the type signature. If you've used C++20 at all, you can think of traits as being somewhat similar to the "concepts" feature in C++20.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM