问题
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