Хранить ссылки на себя - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь создать сеть узлов в 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();
}

Это, однако, дает

не может выйти из заимствованного контента

at:

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

Поскольку *self перемещается из заимствованного содержимого в &Rc::new(*self).Любые идеи о том, как каждый узел может отслеживать все другие узлы в сети?

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

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();
0 голосов
/ 04 июня 2018

Вы должны разделить свой узел и свою сеть, потому что ваша сеть должна взять на себя владение вашим узлом, чтобы создать 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);
}
...