How to init a Rust vector with a generator function?

时光毁灭记忆、已成空白 提交于 2020-01-13 09:07:25

问题


Hopping between languages can be painful. Idioms of one language "feel good" and one starts to look for the same idioms in other languages.

In F#, there is a way to init an array with the help of a generator function. Array.init n generator. Now, that I hopped to Rust for a little while, I wonder if there is a similar facility in place or if I have to create myself such a facility.

Studying Rust standard library documentation about vectors, I could not find anything similar to what I am looking for.

// Looking for something similar to:
Vec<T>::init(n : usize, generator : F) -> Vec<T> 
    where F: Fn(usize) -> T {
    // ...
}

Maybe it works differently in Rust, by means of iterators. But I must admit, that Rust iterators (and their myriads of flavors) are still a tad foggy to my simple mind.


回答1:


You can use a range withing a map and then collect the results.

Like in the example for F# docs:

let my_vector : Vec<i32> = (1..11).map(|x| x*x).collect();

Check this live example




回答2:


Though @Netwave provides the answer, I'd point to a solution which uses it and provides both more reusability and readability.

  1. Define a generic function, playground:

    fn initialize<T>(count: usize, f: fn(usize) -> T) -> Vec<T> {
        (0..count).map(f).collect()
    }
    
    fn main() {
        let my_vector = initialize(10, |i| i as i32);
        for e in my_vector {
             println!("{}", e);
        }
    }
    
  2. Define a trait, implement it for whatever you want and use it, playground:

    trait Initializer<T> {
        fn initialize(count: usize, f: fn(usize) -> T) -> Vec<T> {
            (0..count).map(f).collect()
        }
    }
    
    impl<T> Initializer<T> for Vec<T> {}
    
    fn main() {
        let my_vector = Vec::initialize(10, |i| i as i32);
        for e in my_vector {
            println!("{}", e);
        }
    }
    

    or more general way:

    trait Initializer<T, U> {
        fn initialize(count: usize, f: fn(usize) -> U) -> T;
    }
    
    impl<T: std::iter::FromIterator<U>, U> Initializer<T, U> for T {
        fn initialize(count: usize, f: fn(usize) -> U) -> T {
            (0..count).map(f).collect::<T>()
        }
    }
    
    fn main() {
        let my_vector = Vec::initialize(10, |i| i as i32);
        for e in my_vector {
            println!("{}", e);
        }
    }
    
  3. Write a macro, playground:

    macro_rules! vec_init {
        ($count: expr, $f: expr) => { (0..$count).map($f).collect() }
    }
    
    fn main() {
        let my_vector: Vec<i32> = vec_init!(10, |i| i as i32);
    }
    

The base still the same is in the @Netwave's answer. You've asked that you want something like:

// Looking for something similar to:
Vec<T>::init(n : usize, generator : F) -> Vec<T> 
    where F: Fn(usize) -> T {
    // ...
}

And there is exactly this code in the second item.




回答3:


Pretty late to this party, but: resize_with



来源:https://stackoverflow.com/questions/48021408/how-to-init-a-rust-vector-with-a-generator-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!