使用`move`关键字的闭包如何创建FnMut闭包?

时间:2018-05-02 13:28:30

标签: rust

到目前为止,我认为move |...| {...}会在闭包内移动变量,闭包只会实现FnOnce,因为你只能移动变量一次。然而,令我惊讶的是,我发现此代码有效:

extern crate futures;

use futures::stream;
use futures::stream::{Stream, StreamExt};
use std::rc::Rc;

#[derive(Debug)]
struct Foo(i32);

fn bar(r: Rc<Foo>) -> Box<Stream<Item = (), Error = ()> + 'static> {
    Box::new(stream::repeat::<_, ()>(()).map(move |_| {
        println!("{:?}", r);
    }))
}

fn main() {
    let r = Rc::new(Foo(0));
    let _ = bar(r);
}

尽管map有这个签名:

fn map<U, F>(self, f: F) -> Map<Self, F>
where
    F: FnMut(Self::Item) -> U, 

令我惊讶的是,在使用FnMut关键字时创建了move封闭,它的生命周期甚至为'static。我在哪里可以找到有关move的一些详细信息?或者它是如何运作的?

2 个答案:

答案 0 :(得分:7)

是的,这一点非常令人困惑,我认为Rust书的措辞有所贡献。在我阅读之后,我的想法和你一样:move闭包必须是FnOnce,而非move闭包是FnMut(也可能是Fn)。但这与实际情况有点相反。

闭包可以从创建它的范围捕获值。 move控制这些值如何进入闭包:移动或引用。但是它们是如何在之后使用来捕获它们来确定闭包是否为FnMut

如果闭包的主体消耗它捕获的任何值,则闭包只能是FnOnce。关闭第一次运行后,消耗该值,它不能再次运行。

正如您所提到的,您可以通过调用drop或其他方式在闭包内部使用一个值,但最常见的情况是从闭包中返回它,从而将其移出关闭。这是最简单的例子:

let s = String::from("hello world");
let my_fnonce = move || { s };

如果闭包的主体没有消耗任何捕获,那么它是FnMut,无论是move还是Fn。如果它也没有改变任何捕获,它也是Fn;任何FnMut的闭包也是let s = "hello world"; let my_fn = move || { s.length() } 。这是一个简单的例子,虽然不是很好的例子。

move

摘要

FnMut修饰符控制在创建时,如何将捕获移动关闭。 <VirtualHost *:80> ServerName example.com DocumentRoot /var/www/example/ <Location /node> ProxyPass http://127.0.0.1:8124/ ProxyPassReverse http://127.0.0.1:8124/ </Location> </VirtualHost> 成员资格取决于捕获在执行时如何从移出关闭(或以其他方式消费)。

答案 1 :(得分:4)

  

到目前为止,我认为 <div class="para"> </div> 将在闭包内移动变量,闭包只会实现.para{ z-index: -100; height: 160vh; width: 100%; margin-top: -40rem; background: url("back1.jpg") no-repeat center; background-size: cover; background-attachment: fixed; -webkit-clip-path: polygon(0 22%, 100% 0, 100% 79%, 0% 100%); clip-path: polygon(0 22%, 100% -800px, 100% 60%, 0% 100%); transform: rotate(10deg); } ,因为你只能移动一次变量。

创建闭包时移动变量,而不是在调用它时移动。由于您只创建了一个闭包,因此移动只发生一次 - 无论move |...| {...}调用该函数的频率如何。