存储对自我

时间:2018-06-04 09:26:59

标签: rust weak-references

我正在尝试在Rust中创建一个节点网络,我希望网络中的每个节点都能够知道每个其他连接节点。我认为这可以通过弱Rc来完成,如下所示:

use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}

impl Node {
    fn connect_to_network(&mut self) {
        self.known_nodes
            .borrow_mut()
            .push(Rc::downgrade(&Rc::new(*self)));
    }
}

fn main() {
    let known_nodes = Rc::new(RefCell::new(Vec::new()));
    let node_one = Node {
        name: "node1",
        known_nodes: known_nodes.copy(),
    };
    node_one.connect_to_network();
    let node_two = Node {
        name: "node2",
        known_nodes: known_nodes.copy(),
    };
    node_two.connect_to_network();
}

然而这会产生

  

无法摆脱借来的内容

在:

self.known_senders.borrow_mut().push(Rc::downgrade(&Rc::new(*self)));

因为*self已移出&Rc::new(*self)中的借用内容。 关于每个节点如何跟踪网络中所有其他节点的任何想法?

2 个答案:

答案 0 :(得分:3)

您应该将节点和网络分开,因为您的网络必须获取节点的所有权才能创建Rc(或者至少,它必须采用已创建的Rc 1}})。这是一个更好的设计,可以达到你想要的效果:

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;

#[derive(Debug)]
struct Node {
    name: String,
}

#[derive(Default, Debug)]
struct Network {
    nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}

impl Network {
    fn add_node(&mut self, node: Node) -> Rc<Node> {
        let node = Rc::new(node);
        self.nodes.borrow_mut().push(Rc::downgrade(&node));

        node
    }
}

fn main() {
    let mut network = Network::default();
    let node_1 = Node { name: "node_1".into() };
    let node_2 = Node { name: "node_2".into() };

    let _node_1 = network.add_node(node_1);
    let _node_2 = network.add_node(node_2);
}

如果要存储对self的引用,可以执行以下操作:

use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

type MutableNode = Rc<RefCell<Node>>;
type Network = Rc<RefCell<Vec<Weak<RefCell<Node>>>>>;

struct Node {
    name: String,
    others: Network,
}

impl Node {
    fn new(name: String) -> MutableNode {
        let node = Rc::new(RefCell::new(Node {
            name,
            others: Rc::new(RefCell::new(Vec::new())),
        }));
        {
            let tmp = node.borrow();
            tmp.others.borrow_mut().push(Rc::downgrade(&node));
        }

        node
    }

    fn add_node(&mut self, name: String) -> MutableNode {
        let others = self.others.clone();
        let node = Rc::new(RefCell::new(Node { name, others }));
        self.others
            .borrow_mut()
            .push(Rc::downgrade(&node));

        node
    }

    fn len(&self) -> usize {
        self.others.borrow().len()
    }
}

fn main() {
    let node_0 = Node::new("node_0".into());
    let node_1 = node_0.borrow_mut().add_node("node_1".into());
    let node_2 = node_0.borrow_mut().add_node("node_2".into());

    assert_eq!(node_0.borrow().len(), 3);
    assert_eq!(node_1.borrow().len(), 3);
    assert_eq!(node_2.borrow().len(), 3);
}

答案 1 :(得分:0)

Rc::new(value:T)使用value。您的函数只借用它,因此您无法调用Rc::new(*self)

我建议你像上面的答案一样创建一个网络结构。或者您可以将节点包装在Rc<RefCell<Node>>中,如下所示:

use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

#[derive(Debug)]
struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}

impl Node {
    fn connect_to_network(&mut self,ref_to_self: Weak<RefCell<Node>>) {
        self.known_nodes
            .borrow_mut()
            .push(ref_to_self);
    }
}

fn main() {
    let known_nodes = Rc::new(RefCell::new(Vec::new()));
    let node_one = Rc::new(RefCell::new(Node {
        name: "node1".into(),
        known_nodes: known_nodes.clone(),
    }));
    node_one.borrow_mut().connect_to_network(Rc::downgrade(&node_one));
    let node_two = Rc::new(RefCell::new(Node {
        name: "node2".into(),
        known_nodes: known_nodes.clone(),
    }));
    node_two.borrow_mut().connect_to_network(Rc::downgrade(&node_two));
    println!("{:?}",known_nodes.borrow()[0].upgrade());
    println!("{:?}",known_nodes.borrow()[1].upgrade());
    drop(node_one);
    drop(node_two);
    println!("{:?}",known_nodes.borrow()[0].upgrade());
    println!("{:?}",known_nodes.borrow()[1].upgrade());
}

在这种情况下,您实际上并不需要connect_to_network功能,您可以直接将Weak<RefCell<Node>>添加到known_nodes

如果您希望代码看起来更干净,可以像这样向Rc<RefCell<Node>>引入新类型别名

struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}

type RcNode = Rc<RefCell<Node>>;

trait Connectable {
    fn connect_to_network(&self);
}

impl Connectable for RcNode {
    fn connect_to_network(&self){
        let node = self.borrow_mut();
        node.known_nodes.borrow_mut().push(Rc::downgrade(self));
    }
}

所以你可以打电话给

let node_one:RcNode = Rc::new(RefCell::new(Node {
    name: "node1".into(),
    known_nodes: known_nodes.clone(),
}));
node_one.connect_to_network();