闭包引用其所附着的对象

问题描述 投票:0回答:1

这里是一个假设的套接字的代码(playground here),当收到一些数据时,它将写回数据(如闭包中定义)。

pub struct Socket {
    on_message_received: Box<dyn FnMut(&Vec<u8>, &mut Socket)>,
}

impl Socket {
    pub fn new(on_message_received: Box<dyn FnMut(&Vec<u8>, &mut Socket)>) -> Self {
        Self {
            on_message_received,
        }
    }

    pub fn read(&mut self, fake_data: &Vec<u8>) {
        (self.on_message_received)(fake_data, self);
    }

    pub fn write(&mut self, data: Vec<u8>) {
        println!(
            "Pretend this requires a mutable reference to self {:?}",
            data
        );
    }
}

fn main() {
    let mut socket = Socket::new(Box::new(|data, socket| {
        socket.write(data.clone());
    }));
    socket.read(&vec![1, 2, 3]);
}

(self.on_message_received)(fake_data, self);
无法编译,因为我们
cannot borrow 
*self
 as mutable more than once at a time
。我理解这一点,但想不出解决方法。

我还尝试过(其他playground)在setter中(而不是在构造函数中)定义闭包,并使闭包捕获对套接字的引用(而不是让闭包通过对套接字的引用来调用) ).

但最终,我总是面临同样的问题,即发生可变引用的双重借用。 🤔

rust closures
1个回答
0
投票

如果你可以使用

Fn
而不是
FnMut
那么你可以通过使用
Arc
而不是
Box
来解决这个问题,并在调用闭包之前克隆
Arc

use std::sync::Arc;

pub struct Socket {
    on_message_received: Arc<dyn Fn(&Vec<u8>, &mut Socket)>,
}

impl Socket {
    pub fn new(on_message_received: Arc<dyn Fn(&Vec<u8>, &mut Socket)>) -> Self {
        Self {
            on_message_received,
        }
    }

    pub fn read(&mut self, fake_data: &Vec<u8>) {
        let cb = self.on_message_received.clone();
        (cb)(fake_data, self);
    }

    pub fn write(&mut self, data: Vec<u8>) {
        println!(
            "Pretend this requires a mutable reference to self {:?}",
            data
        );
    }
}

fn main() {
    let mut socket = Socket::new(Arc::new(|data, socket| {
        socket.write(data.clone());
    }));
    socket.read(&vec![1, 2, 3]);
}

(游乐场)

通过克隆

Arc
,我们获得了闭包的句柄,该句柄独立于
self
的生命周期,因此不需要借用
self

值得注意的是,这种方法允许

Socket::read
完全可重入——闭包可以毫无问题地调用
socket.read()
(当然,除了无限递归的可能性之外)。

© www.soinside.com 2019 - 2024. All rights reserved.