ZhangHanDong / tao-of-rust-codes

《Rust编程之道》随书源码
https://ruststudy.github.io/tao_of_rust_docs/tao_of_rust/
MIT License
1.19k stars 172 forks source link

「第六章」关于闭包和所有权的描述需要修正 #199

Closed ZhangHanDong closed 5 years ago

ZhangHanDong commented 5 years ago

页码与行数


在「闭包和所有权」小节的内容,所有示例都是连续的。从第一个示例开始,闭包捕获了不可变借用,实现Fn,一直到下面「使用move 关键字自动实现Fn」小节,也是对应开始的这个示例。

我想表达的意思是: 「对于捕获不可变借用来说,即使使用move,也还是可以实现Fn。」,但这样的描述,可能会引起读者的误会。

所以,需要修正相关内容描述,来提示读者,示例之间上下是有联系的。

ZhangHanDong commented 5 years ago

「使用move 关键字自动实现Fn」改为「使用move关键字自动实现Fn的情况」

在内容描述中添加: 「对于捕获不可变借用的情况,即使使用move关键字,仅仅是将捕获变量的所有权转移到了闭包中,但不影响闭包自身的实现(Fn/FnMut/FnOnce)的规则」。

ZhangHanDong commented 5 years ago

这里有两个维度:

  1. 闭包实现的是Fn/FnMut/FnOnce的哪一种?
  2. 闭包有没有自动实现Copy?
#![feature(fn_traits)]
fn call<F: FnOnce()>(f: F) { f() }

fn main() {
    let mut x = 0;
    let mut incr_x = || x += 1;
    incr_x.call_mut(()); // 闭包实现的是FnMut
    call(incr_x);

    // 使用move使得所有权转移,但是复制语义的捕获变量,会让闭包自动实现Copy
    let mut x = 0;
    let mut incr_x = move || x += 1;
    incr_x.call_mut(()); // 闭包实现的是FnMut
    call(incr_x);
    call(incr_x);

    let mut x = vec![];
    let mut expend_x =  move|| x.push(42);
    expend_x.call_mut(());  
    call(expend_x);  
    // call(expend_x); // 闭包并未实现Copy,因为捕获变量是是移动语义
}

然后再看 move关键字影响的是哪个维度?