为什么使用“move”关键字的闭包不被推断为 FnOnce?

Pat*_*tas 5 closures rust

我正在使用《理解 Rust 中的闭包》中的示例。。我定义了以下结构:

struct MyStruct {
    text: &'static str,
    number: u32,
}

impl MyStruct {
    fn new(text: &'static str, number: u32) -> MyStruct {
        MyStruct {
            text: text,
            number: number,
        }
    }
    // We have to specify that 'self' is an argument.
    fn get_number(&self) -> u32 {
        self.number
    }
    // We can specify different kinds of ownership and mutability of self.
    fn inc_number(&mut self) {
        self.number += 1;
    }
    // There are three different types of 'self'
    fn destructor(self) {
        println!("Destructing {}", self.text);
    }
}
Run Code Online (Sandbox Code Playgroud)

我创建了这些“测试”函数来根据编译时错误对闭包进行分类:

fn is_fn<A, R>(_x: fn(A) -> R) {}
fn is_Fn<A, R, F: Fn(A) -> R>(_x: &F) {}
fn is_FnMut<A, R, F: FnMut(A) -> R>(_x: &F) {}
fn is_FnOnce<A, R, F: FnOnce(A) -> R>(_x: &F) {}
Run Code Online (Sandbox Code Playgroud)

本文演示了以下示例作为FnOnce闭包:

let obj1 = MyStruct::new("Hello", 15);
let obj2 = MyStruct::new("More Text", 10);
// obj1 is owned by the closure
let mut closure4 = move |x: &MyStruct| {
    obj1.destructor();
    x.get_number()
};
is_FnMut(&closure4);
Run Code Online (Sandbox Code Playgroud)

这有一个编译错误:

struct MyStruct {
    text: &'static str,
    number: u32,
}

impl MyStruct {
    fn new(text: &'static str, number: u32) -> MyStruct {
        MyStruct {
            text: text,
            number: number,
        }
    }
    // We have to specify that 'self' is an argument.
    fn get_number(&self) -> u32 {
        self.number
    }
    // We can specify different kinds of ownership and mutability of self.
    fn inc_number(&mut self) {
        self.number += 1;
    }
    // There are three different types of 'self'
    fn destructor(self) {
        println!("Destructing {}", self.text);
    }
}
Run Code Online (Sandbox Code Playgroud)

这就说得通了。根据我的理解,编译器推断该值已移至闭包中,因为调用了析构函数。

我试图看看还有什么原因导致关闭被推断为FnOnce。我将闭包声明为move闭包:

let obj1 = MyStruct::new("Hello", 15);
let obj2 = MyStruct::new("More Text", 10);
// obj1 is owned by the closure
let mut closure4 = move |x: &MyStruct| {
    obj1.get_number();
    x.get_number()
};
is_Fn(&closure4);
is_FnMut(&closure4);
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,这实际上已经过去了,所以这个闭包实际上被认为是也Fn,而不是完全FnOnce像我预期的那样。这是为什么?我认为如果一个值被移入闭包,它不会实现,Fn而只会实现FnOnce

所以我想,“好吧,也许不知何故并obj1没有真正进入关闭状态,让我测试一下”。obj1所以我尝试在构造后以任何方式使用closure4,编译器表明obj1确实已移入闭包:

let obj1 = MyStruct::new("Hello", 15);
let obj2 = MyStruct::new("More Text", 10);
// obj1 is owned by the closure
let mut closure4 = move |x: &MyStruct| {
    obj1.get_number();
    x.get_number()
};
obj1.get_number();
Run Code Online (Sandbox Code Playgroud)
fn is_fn<A, R>(_x: fn(A) -> R) {}
fn is_Fn<A, R, F: Fn(A) -> R>(_x: &F) {}
fn is_FnMut<A, R, F: FnMut(A) -> R>(_x: &F) {}
fn is_FnOnce<A, R, F: FnOnce(A) -> R>(_x: &F) {}
Run Code Online (Sandbox Code Playgroud)

有人可以为我启发这种行为吗?对于不实现fn、、、而仅实现的闭包Fn,必须满足什么条件?FnMutFnOnce