【问题标题】:Arc<Mutex<T>> inside closure: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`闭包内的 Arc<Mutex<T>>:期望实现 `Fn` 特征的闭包,但此闭包仅实现 `FnOnce`
【发布时间】:2021-03-06 04:30:38
【问题描述】:

我正在尝试与闭包共享Arc&lt;Mutex&lt;T&gt;&gt;。我收到closure is FnOncebecause it moves the variableshared_wake_deque_ out of its environment的错误:

use core::task::{Context, Poll, Waker};
use hyper::client::connect::{Connection, Connected};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

pub type OnPollRead = Arc<dyn Fn(&mut Context<'_>, &mut tokio::io::ReadBuf<'_>) -> Poll<std::io::Result<()>> + Send + Sync>;
pub type OnPollWrite = Arc<dyn Fn(&mut Context<'_>, &[u8]) -> Poll<core::result::Result<usize, std::io::Error>> + Send + Sync>;

#[derive(Clone)]
pub struct CustomTransporter {
    on_poll_read: Option<OnPollRead>,
    on_poll_write: Option<OnPollWrite>,
}

pub struct OVPNClient {
}

impl OVPNClient {
    pub fn send(&self, buffer: &[u8]) {
        
    }
}

unsafe impl Send for OVPNClient {}


unsafe impl Send for CustomTransporter {}

impl CustomTransporter {
    pub fn new(on_poll_read: Option<OnPollRead>, on_poll_write: Option<OnPollWrite>) -> CustomTransporter {
        CustomTransporter{
            on_poll_read: on_poll_read,
            on_poll_write: on_poll_write
        }
    }
}

fn main () {
    let openvpn_client = Arc::new(Mutex::new(OVPNClient{}));

    let shared_wake_deque = Arc::new(Mutex::new(VecDeque::<Waker>::new()));
    
    let shared_wake_deque_ = shared_wake_deque.clone();
    let on_poll_read = Arc::new(|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        let shared_wake_deque__ = shared_wake_deque_;
        Poll::Ready(Ok(()))
    });

    let on_poll_write = Arc::new(|context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
        openvpn_client.lock().unwrap().send(buffer);
        Poll::Ready(Ok(0))
    });

    let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
}

错误:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/main.rs:44:33
   |
44 |     let on_poll_read = Arc::new(|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `Fn`
45 |         let shared_wake_deque__ = shared_wake_deque_;
   |                                   ------------------ closure is `FnOnce` because it moves the variable `shared_wake_deque_` out of its environment
...
54 |     let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
   |                                                 ------------ the requirement to implement `Fn` derives from here

我知道移动只能发生一次。我什至没有关闭move。如您所见,我正在尝试使用Arc&lt;Mutex&lt;T&gt;&gt; 的克隆,所以我并没有完全移动它。你可以看到我尝试了克隆,所以我移动了一个仅在此闭包上使用的变量,并且不再使用,但它不起作用。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d996163f5d2a6e9322af9a7472581ce6

【问题讨论】:

    标签: rust


    【解决方案1】:

    因为你有

    let shared_wake_deque__ = shared_wake_deque_;
    

    作为一个简单的赋值,和

    没有区别
    let foo = vec![];
    let foo2 = foo;
    

    运行代码将 vec 的所有权从 foo 转移到 foo2。因为您在 lambda 中具有此功能,所以运行显式将 shared_wake_deque_ 值的所有权转移到 shared_wake_deque__,这意味着不能再使用 shared_wake_deque_。为此,要求on_poll_read 只能运行一次,否则会有多个事物试图拥有同一个对象(两者都是on_poll_read,因为它需要拥有它才能在一些未来的电话,而之前任何电话中的shared_wake_deque__ 也仍然必须拥有它)。由于这将违反 Rust 的安全保证,因为某些东西只能归一物所有,因此您会收到此错误。

    很可能,您想要的是给我们一个参考,例如

    let shared_wake_deque__ = &shared_wake_deque_;
    

    通过使用对shared_wake_deque_ 的引用,允许闭包多次运行并给出多个共享引用。但是,仅凭这一点,您就会得到

    error[E0597]: `shared_wake_deque_` does not live long enough
    

    因为你试图引用一个在闭包外声明的变量,而闭包可以在shared_wake_deque_ 被删除后运行。为了解决那个,你需要闭包来获得shared_wake_deque_的所有权,这是通过使用move关键字来完成的,例如

    let on_poll_read = Arc::new(move |context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        let shared_wake_deque__ = &shared_wake_deque_;
    

    那么on_poll_write 也会出现同样的问题,所以也需要move

    let on_poll_write = Arc::new(move |context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
    

    (Rust playground)

    【讨论】:

      猜你喜欢
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2015-07-22
      • 2023-01-14
      • 2022-09-24
      • 1970-01-01
      • 2015-11-20
      相关资源
      最近更新 更多