Store references to self

北城余情 提交于 2019-12-24 20:30:28

问题


I am trying to create a network of nodes in Rust, where I want every node in the network to be aware of every other connected node. I thought that this could be done with weak Rc's, like this:

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();
}

This however yields

cannot move out of borrowed content

at:

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

Because *self is moved out of borrowed content in the &Rc::new(*self). Any ideas, on how each node can keep track of all the other nodes in the network?


回答1:


You should separate your node and your network, because your network must take the ownership of your node to create an Rc (or at least, it must take an already created Rc). Here is a better design that achieves what you want:

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);
}

If you want to store a reference to self, you can do this:

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);
}



回答2:


Rc::new(value:T) consume the value.Your function only borrow it, so you can't call Rc::new(*self)

I would recommend you to create a Network struct like the above answer. Or you can wrap your node in Rc<RefCell<Node>> like this:

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());
}

Which in this case you don't really need connect_to_network function, you can just add each Weak<RefCell<Node>> to known_nodes directly

If you want the code to look cleaner, you can introduce a new type alias to Rc<RefCell<Node>> like this

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));
    }
}

so then you can call

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


来源:https://stackoverflow.com/questions/50677344/store-references-to-self

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!