函数中的闭包

闭包是伟大的。那么我们如何把它们放到自己的函数中呢?

你可以创建自己的函数来接受闭包,但是在函数里面就不那么自由了,你必须决定类型。在函数外部,一个闭包可以在FnFnMutFnOnce之间自行决定,但在函数内部你必须选择一个。最好的理解方式是看几个函数签名。 这里是.all()的那个。我们记得,它检查一个迭代器,看看所有的东西是否是true(取决于你决定是true还是false)。它的部分签名是这样说的。

#![allow(unused)]
fn main() {
    fn all<F>(&mut self, f: F) -> bool    // 🚧
    where
        F: FnMut(Self::Item) -> bool,
}

fn all<F>:这告诉你有一个通用类型F。一个闭包总是泛型,因为每次都是不同的类型。

(&mut self, f: F):&mut self告诉你这是一个方法。f: F通常你看到的是一个闭包:这是变量名和类型。 当然,fF并没有什么特别之处,它们可以是不同的名字。如果你愿意,你可以写my_closure: Closure--这并不重要。但在签名中,你几乎总是看到f: F

接下来是关于闭包的部分:F: FnMut(Self::Item) -> bool。在这里,它决定了闭包是 FnMut,所以它可以改变值。它改变了Self::Item的值,这是它所取的迭代器。而且它必须返回 truefalse

这里是一个更简单的签名,有一个闭包。

#![allow(unused)]
fn main() {
fn do_something<F>(f: F)    // 🚧
where
    F: FnOnce(),
{
    f();
}
}

这只是说它接受一个闭包,取值(FnOnce=取值),而不返回任何东西。所以现在我们可以调用这个什么都不取的闭包,做我们喜欢做的事情。我们将创建一个 Vec,然后对它进行迭代,只是为了展示我们现在可以做什么。

fn do_something<F>(f: F)
where
    F: FnOnce(),
{
    f();
}

fn main() {
    let some_vec = vec![9, 8, 10];
    do_something(|| {
        some_vec
            .into_iter()
            .for_each(|x| println!("The number is: {}", x));
    })
}

一个更真实的例子,我们将再次创建一个 City 结构体。这次 City 结构体有更多关于年份和人口的数据。它有一个 Vec<u32> 来表示所有的年份,还有一个 Vec<u32> 来表示所有的人口。

City有两个方法:new()用于创建一个新的City, .city_data()有个闭包参数。当我们使用 .city_data() 时,它给我们提供了年份和人口以及一个闭包,所以我们可以对数据做我们想做的事情。闭包类型是 FnMut,所以我们可以改变数据。它看起来像这样:

#[derive(Debug)]
struct City {
    name: String,
    years: Vec<u32>,
    populations: Vec<u32>,
}

impl City {
    fn new(name: &str, years: Vec<u32>, populations: Vec<u32>) -> Self {

        Self {
            name: name.to_string(),
            years,
            populations,
        }
    }

    fn city_data<F>(&mut self, mut f: F) // We bring in self, but only f is generic F. f is the closure

    where
        F: FnMut(&mut Vec<u32>, &mut Vec<u32>), // The closure takes mutable vectors of u32
                                                // which are the year and population data
    {
        f(&mut self.years, &mut self.populations) // Finally this is the actual function. It says
                                                  // "use a closure on self.years and self.populations"
                                                  // We can do whatever we want with the closure
    }
}

fn main() {
    let years = vec![
        1372, 1834, 1851, 1881, 1897, 1925, 1959, 1989, 2000, 2005, 2010, 2020,
    ];
    let populations = vec![
        3_250, 15_300, 24_000, 45_900, 58_800, 119_800, 283_071, 478_974, 400_378, 401_694,
        406_703, 437_619,
    ];
    // Now we can create our city
    let mut tallinn = City::new("Tallinn", years, populations);

    // Now we have a .city_data() method that has a closure. We can do anything we want.

    // First let's put the data for 5 years together and print it.
    tallinn.city_data(|city_years, city_populations| { // We can call the input anything we want
        let new_vec = city_years
            .into_iter()
            .zip(city_populations.into_iter()) // Zip the two together
            .take(5)                           // but only take the first 5
            .collect::<Vec<(_, _)>>(); // Tell Rust to decide the type inside the tuple
        println!("{:?}", new_vec);
    });

    // Now let's add some data for the year 2030
    tallinn.city_data(|x, y| { // This time we just call the input x and y
        x.push(2030);
        y.push(500_000);
    });

    // We don't want the 1834 data anymore
    tallinn.city_data(|x, y| {
        let position_option = x.iter().position(|x| *x == 1834);
        if let Some(position) = position_option {
            println!(
                "Going to delete {} at position {:?} now.",
                x[position], position
            ); // Confirm that we delete the right item
            x.remove(position);
            y.remove(position);
        }
    });

    println!(
        "Years left are {:?}\nPopulations left are {:?}",
        tallinn.years, tallinn.populations
    );
}

这将打印出我们调用.city_data().的所有时间的结果:

[(1372, 3250), (1834, 15300), (1851, 24000), (1881, 45900), (1897, 58800)]
Going to delete 1834 at position 1 now.
Years left are [1372, 1851, 1881, 1897, 1925, 1959, 1989, 2000, 2005, 2010, 2020, 2030]
Populations left are [3250, 24000, 45900, 58800, 119800, 283071, 478974, 400378, 401694, 406703, 437619, 500000]