< 返回版块

zc58778560 发表于 2021-01-26 17:33

struct A;

fn need_fn<F: Fn()>(c: F) {
    c();
    c();
}

fn demo_fn() {
    let a = A;
    let c = || { let _a = &a; };
    // 为什么c可以被移动所有权2次?
    need_fn(c);
    need_fn(c);
}

评论区

写评论
whfuyn 2021-01-27 23:00

学到了

Note: move closures may still implement Fn or FnMut, even though they capture variables by move. This is because the traits implemented by a closure type are determined by what the closure does with captured values, not how it captures them.

--
👇
uno: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=534a897a7c88eb43a446d55350eb3e52

--
👇
whfuyn: 加个move就不是Fn了,只有FnOnce

uno 2021-01-27 22:26

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=534a897a7c88eb43a446d55350eb3e52

--
👇
whfuyn: 加个move就不是Fn了,只有FnOnce

whfuyn 2021-01-27 21:57

加个move就不是Fn了,只有FnOnce

Playground

fn need_fn<F: Fn()>(_: F) {
    // ...
}

fn main() {
    let s = String::new();
    let f = move || drop(s);
    // error[E0525]: expected a closure that implements the `Fn` trait,
    // but this closure only implements `FnOnce`
    need_fn(f);

}

--
👇
uno:

哪用你那么麻烦,,就我最开始说的,加个move关键字就行了

--
👇
whfuyn: 举个满足Fn但不Copy的栗子。

...

uno 2021-01-27 20:00

哪用你那么麻烦,,就我最开始说的,加个move关键字就行了

--
👇
whfuyn: 举个满足Fn但不Copy的栗子。

...

whfuyn 2021-01-27 17:13

举个满足Fn但不Copy的栗子。

playground

#![feature(fn_traits)]
#![feature(unboxed_closures)]

struct NonCopyableFn;

impl Fn<()> for NonCopyableFn {
    
    extern "rust-call" fn call(&self, _: ()) {
        // ...
    }
}

impl FnMut<()> for NonCopyableFn {
    
    extern "rust-call" fn call_mut(&mut self, _: ()) {
        // ...
    }
}

impl FnOnce<()> for NonCopyableFn {
    type Output = ();
    
    extern "rust-call" fn call_once(self, _: ()) {
        // ...
    }
}

fn need_noncopyable_fn<F: Fn()>(_: F) {
    // ...
}

fn need_copyable_fn<F: Fn() + Copy>(c: F) {
    let _c1 = c;
    let _c2 = c;
}

fn main() {
    need_noncopyable_fn(NonCopyableFn);
    // error[E0277]: the trait bound `NonCopyableFn: Copy` is not satisfied
    // need_copyable_fn(NonCopyableFn);
}
uno 2021-01-27 12:38

正解,,不过要这样表达,可能更清晰一点,即在传递进方法前有很多信息,但是方法参数的约束F只有一个Fn(),所以在方法里是不知道可不可以Copy的。这样写就明白了。

fn need_fn<F: Fn()+Copy>(c: F) {
    let _c1 = c;
    let _c2 = c;
}

--
👇
whfuyn: 因为这里的F是泛型,它不一定Copy

demo_fn里的cCopy的,因为它捕获的所有东西(只有一个共享引用)都是Copy的。

参考:https://doc.rust-lang.org/stable/reference/types/closure.html#other-traits

Bai-Jinlin 2021-01-27 08:01

简单来说就是没使用move的情况下 实现了Fn()的闭包肯定也实现了Copy。但是一个Fn()的闭包假如使用了move的情况下仅当move的变量实现了Copy那闭包才会实现Copy。

闭包还有很多复杂的规则。

whfuyn 2021-01-26 20:51

因为这里的F是泛型,它不一定Copy

demo_fn里的cCopy的,因为它捕获的所有东西(只有一个共享引用)都是Copy的。

参考:https://doc.rust-lang.org/stable/reference/types/closure.html#other-traits

--
👇
zc58778560: ```rust fn need_fn<F: Fn()>(c: F) { let _c1 = c; let _c2 = c; // 报错:Use of moved value }

如果Fn()是复制语义,为什么会报错?
--  
👇  
uno: 
复制语义,你加上move就知道了

作者 zc58778560 2021-01-26 18:56
fn need_fn<F: Fn()>(c: F) {
    let _c1 = c;
    let _c2 = c; // 报错:Use of moved value
}

如果Fn()是复制语义,为什么会报错?

👇
uno: 复制语义,你加上move就知道了

uno 2021-01-26 17:42

复制语义,你加上move就知道了

1 共 10 条评论, 1 页