商店引用自(Store references to self)

2019-11-04 19:28发布

我想创建节点的锈,在这里我想在网络中的每个节点要意识到每一个其他连接节点的网络。 我认为,这可能与弱完成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) 。 任何想法,在每个节点如何跟踪网络中的所有其他节点的?

Answer 1:

您应该分开的节点和网络,因为网络必须将节点创建的所有权Rc (或至少,它必须采取一个已经创建的Rc )。 这里是一个更好的设计,达到你想要什么:

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


Answer 2:

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


文章来源: Store references to self