如何强制借用变量进行关闭?在弯曲中编码 f32



在为 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*调用。第一次循环迭代会消耗它,所以这就是编译器抛出错误的原因。

其次,encoderin 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

我希望这是有帮助的

最新更新