使用 `move` 关键字的闭包如何创建 FnMut 闭包? [英] How can a closure using the `move` keyword create a FnMut closure?

查看:49
本文介绍了使用 `move` 关键字的闭包如何创建 FnMut 闭包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Up to this moment I thought that move |...| {...} would move variables inside a closure and the closure would implement only FnOnce, because you can move variables only once. To my surprise, however, I found that this code works:

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, 

令我惊讶的是,在使用 move 关键字时创建了一个 FnMut 闭包,它甚至具有 'static 生命周期.我在哪里可以找到有关 move 的详细信息?或者它实际上是如何工作的?

It's surprising to me that a FnMut closure was created when using the move keyword and it even has 'static lifetime. Where can I find some details about move? Or how does it actually work?

推荐答案

是的,这一点相当令人困惑,我认为 Rust 书的措辞有所贡献.读完之后,我和你的想法一样:move 闭包必然是 FnOnce,非 move 闭包是FnMut(也可能是 Fn).但这与实际情况有点背道而驰.

Yes, this point is quite confusing, and I think the wording of the Rust book contributes. After I read it, I thought the same as you did: that a move closure was necessarily FnOnce, and that a non-move closure was FnMut (and may also be Fn). But this is kind-of backwards from the real situation.

闭包可以从创建它的作用域中捕获值.move 控制这些值如何进入闭包:通过移动或通过引用.但是,它们被捕获后的使用方式决定了闭包是否为 FnMut.

The closure can capture values from the scope where it's created. move controls how those values go into the closure: either by being moved, or by reference. But it's how they're used after they're captured that determines whether the closure is FnMut or not.

如果闭包的主体消耗了它捕获的任何值,那么闭包只能是 FnOnce.闭包第一次运行并消耗该值后,就无法再次运行.

If the body of the closure consumes any value it captured, then the closure can only be FnOnce. After the closure runs the first time, and consumes that value, it can't run again.

正如您所提到的,您可以通过对其调用 drop 或其他方式来使用闭包内的值,但最常见的情况是从闭包中返回它,它会移动把它关掉.这是最简单的例子:

As you've mentioned, you can consume a value inside the closure by calling drop on it, or in other ways, but the most common case is to return it from the closure, which moves it out of the closure. Here's the simplest example:

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

如果闭包的主体不消耗它的任何捕获,那么它就是 FnMut,无论它是否是 move.如果它也没有改变它的任何捕获,它也是 Fn;Fn 的任何闭包也是 FnMut.这是一个简单的例子,虽然不是很好.

If the body of the closure doesn't consume any of its captures, then it's FnMut, whether it was move or not. If it also doesn't mutate any of its captures, it's also Fn; any closure that is Fn is also FnMut. Here's a simple example, albeit not a very good one.

let s = "hello world";
let my_fn = move || { s.len() }

总结

move 修饰符控制捕获在创建时如何移入闭包.FnMut 成员资格取决于捕获在执行时如何移出闭包(或以其他方式使用).

Summary

The move modifier controls how captures are moved into the closure when it's created. FnMut membership is determined by how captures are moved out of the closure (or consumed in some other way) when it's executed.

这篇关于使用 `move` 关键字的闭包如何创建 FnMut 闭包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆