Update closure.md

修改了行文,更加流畅易于阅读
pull/1249/head
hacktor 1 year ago committed by GitHub
parent 494575c6c8
commit ea00e8390f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -490,9 +490,9 @@ fn exec<'a, F: FnMut(&'a str)>(mut f: F) {
} }
``` ```
我们注意到这段代码中`update_string`没有使用mut关键字修饰而上文我们提到想要在闭包内部捕获可变借用,需要用关键词把该闭包声明为可变类型。我们确实这么做了———`exec(mut f: F)`表明我们的`exec`接收的是一个可变类型的闭包。看似这段代码中`update_string`声明为不可变闭包,但是`exec(mut f: F)`函数接收的又是可变参数,为什么可以正常执行呢? 这段代码中`update_string`没有使用mut关键字修饰而上文提到想要在闭包内部捕获可变借用需要用关键词把该闭包声明为可变类型。我们确实这么做了———`exec(mut f: F)`表明我们的`exec`接收的是一个可变类型的闭包。这段代码中`update_string`看似被声明为不可变闭包,但是`exec(mut f: F)`函数接收的又是可变参数,为什么可以正常执行呢?
是的,rust不可能接受类型不匹配的形参和实参通过编译这说明`update_string`一定是一个可变类型的闭包我们不妨看看rust-analyzer给出的类型标注 rust不可能接受类型不匹配的形参和实参通过编译,我们提供的实参又是可变的,这说明`update_string`一定是一个可变类型的闭包我们不妨看看rust-analyzer自动给出的类型标注:
```rust ```rust
let mut s: String = String::new(); let mut s: String = String::new();
@ -500,15 +500,15 @@ fn exec<'a, F: FnMut(&'a str)>(mut f: F) {
let update_string: impl FnMut(&str) = |str| s.push_str(str); let update_string: impl FnMut(&str) = |str| s.push_str(str);
``` ```
这段代码非常清晰的说明了 `update_string` 实现了 `FnMut` 特征。 rust-analyzer给出的类型标注非常清晰的说明了 `update_string` 实现了 `FnMut` 特征。
不是说需要用mut关键词修饰才能将闭包声明为可变类型吗?事实上,`FnMut`只是trait的名字声明`FnMut`的变量和要不要mut没啥关系`FnMut`是推导出的trait类型,`mut`是rust语言层面的一个修饰符用于声明一个绑定是可变的。Rust从trait类型系统和语言修饰符两方面保障了我们的程序正确运行。 为什么`update_string`没有用`mut`修饰却是一个可变类型的闭包?事实上,`FnMut`只是trait的名字声明变量为`FnMut`和要不要mut没啥关系`FnMut`是推导出的特征类型,`mut`是rust语言层面的一个修饰符用于声明一个绑定是可变的。Rust从特征类型系统和语言修饰符两方面保障了我们的程序正确运行。
我们在使用`FnMut`类型闭包时需要捕获外界的可变借用,因此我们常常搭配`mut`修饰符使用。但我们要始终记住,二者是相互独立的。 我们在使用`FnMut`类型闭包时需要捕获外界的可变借用,因此我们常常搭配`mut`修饰符使用。但我们要始终记住,二者是相互独立的。
因此,让我们再回头分析一下这段代码:在`main`函数中,首先创建了一个可变的字符串`s`,然后定义了一个可变类型闭包`update_string`,该闭包接受一个字符串参数并将其追加到`s`中。接下来调用了`exec`函数,并将`update_string`闭包的所有权移交给它。最后打印出了字符串`s`的内容。 因此,让我们再回头分析一下这段代码:在`main`函数中,首先创建了一个可变的字符串`s`,然后定义了一个可变类型闭包`update_string`,该闭包接受一个字符串参数并将其追加到`s`中。接下来调用了`exec`函数,并将`update_string`闭包的所有权移交给它。最后打印出了字符串`s`的内容。
细心的读者可能已经注意到了,在我们对代码的分析中提到`update_string`闭包的所有权被移交给了`exec`函数。这说明`update_string`没有实现copy trait但并不是所有闭包都没有实现copy trait闭包是否会实现copy trait总结一下就是只要闭包捕获的类型都实现`Copy`的话,这个闭包就默认实现了`Copy` 细心的读者可能注意到,我们在上文的分析中提到`update_string`闭包的所有权被移交给了`exec`函数。这说明`update_string`没有实现`Copy`特征,但并不是所有闭包都没有实现`Copy`特征,闭包自动实现`Copy`特征的规则是,只要闭包捕获的类型都实现了`Copy`特征的话,这个闭包就会默认实现`Copy`特征
我们来看一个例子: 我们来看一个例子:
@ -517,7 +517,7 @@ let s = String::new();
let update_string = || println!("{}",s); let update_string = || println!("{}",s);
``` ```
这里拿到的是`s`的不可变引用,所以是能`Copy`的。而如果拿到的是`s`的所有权或可变引用,都是不能`Copy`的。我们刚刚的代码就属于第二类,拿到的是`s`的可变引用,是没有实现`Copy`的 这里取得的是`s`的不可变引用,所以是能`Copy`的。而如果拿到的是`s`的所有权或可变引用,都是不能`Copy`的。我们刚刚的代码就属于第二类,取得的是`s`的可变引用,没有实现`Copy`
```rust ```rust
// 拿所有权 // 拿所有权

Loading…
Cancel
Save