在为 bendy 实现编码特性时,我尝试了以下方法:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Default, Clone)]
pub struct MyFloot {
pub density: f32,
}
use bendy::encoding::{Error, ToBencode};
impl ToBencode for MyFloot {
const MAX_DEPTH: usize = 1;
fn encode(&self, encoder: bendy::encoding::SingleItemEncoder) -> Result<(), Error> {
self.density
.to_be_bytes()
.iter()
.map(|b| encoder.emit_int(*b));
Ok(())
}
}
产生以下错误:
error[E0507]: cannot move out of `encoder`, a captured variable in an `FnMut` closure
--> srcmain.rs:17:22
|
13 | fn encode(&self, encoder: bendy::encoding::SingleItemEncoder) -> Result<(), Error> {
| ------- captured outer variable
...
17 | .map(|b| encoder.emit_int(*b));
| --- ^^^^^^^ ------------ `encoder` moved due to this method call
| | |
| | move occurs because `encoder` has type `SingleItemEncoder<'_>`, which does not implement the `Copy` trait
| captured by this `FnMut` closure
|
note: this function takes ownership of the receiver `self`, which moves `encoder`
--> .cargoregistrysrcgithub.com-1ecc6299db9ec823bendy-0.3.3srcencodingencoder.rs:257:42
|
257 | pub fn emit_int<T: PrintableInteger>(self, value: T) -> Result<(), Error> {
| ^^^^
但是我不能用这个来理解移动语义。.
- 为什么关闭会在这里拥有
encoder
的所有权,尽管省略了move
? (我假设确实如此) - 为什么需要将其移出上下文?
- 这甚至意味着什么?
我明白了!
首先,消耗encoder
的不是关闭,而是emit*
调用。第一次循环迭代会消耗它,所以这就是编译器抛出错误的原因。
其次,encoder
in bendy 在 trait 中具有emit_bytes
功能,可以在这里使用:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Default, Clone)]
pub struct MyFloot {
pub density: f32,
}
use bendy::encoding::{Error, ToBencode};
impl ToBencode for MyFloot {
const MAX_DEPTH: usize = 1;
fn encode(&self, encoder: bendy::encoding::SingleItemEncoder) -> Result<(), Error> {
encodert.emit_bytes(self.density.to_be_bytes());
Ok(())
}
}
这个闭包获得了encoder
的所有权,因为它调用了emit_int
,它需要encoder
的所有权。map
需要一个可以运行任意次数的闭包,这就是为什么它需要FnMut
而不是FnOnce
。
请注意,Iterator::map
是懒惰的,所以如果编译(比如用Encoder
),它实际上不会做任何事情。你可以打电话给Iterator::for_each
:
self.density
.to_be_bytes()
.iter()
.for_each(|b| encoder.emit_int(*b));
或致电array::map
:
self.density
.to_be_bytes()
.map(|b| encoder.emit_int(b));
或者只使用 for 循环:
for b in self.density.to_be_bytes() {
encoder.emit_int(b)
}
为什么关闭会在这里拥有
encoder
的所有权,尽管省略了move
?
因为emit_int
方法按值接收self
:
pub fn emit_int<T: PrintableInteger>(self, value: T) -> Result<(), Error>
因此,必须将该值移动到闭包中才能调用此方法。
闭包上的move
强制编译器将引用的变量移动到闭包中,但缺少move
并不禁止编译器将引用的变量移动到闭包中。 如果在需要移动变量的上下文中在闭包中使用变量,它仍然会移动变量。
https://docs.rs/bendy/0.3.3/bendy/encoding/struct.SingleItemEncoder.html#method.emit_int
在提供的链接中,您可以查看弯曲 crate 的文档,您会发现在bendy::encoding::SingleItemEncoder
结构上实现的emit_init
方法将self
作为接收器,这意味着该函数拥有它作为方法调用的 SingleItemEncoder 实例的所有权。在您的情况下,参数encoder
就是这样一个实例,因此当您在第 17 行对其调用emit_init
方法时,将获得变量的所有权。因此,rust 推断闭包需要获得此变量的所有权以促进此方法调用,这意味着变量的移动不必使用"move"关键字,该关键字在不需要移动的情况下强制移动。
要了解搬家的概念,请参阅书中: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#variables-and-data-interacting-with-move
我希望这是有帮助的