Created
August 26, 2016 16:00
-
-
Save anonymous/8e558248f01713d51aa669a9cd18e34c to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::RefCell; | |
use std::rc::Rc; | |
// A graph can be represented in several ways. For the sake of illustrating how | |
// interior mutability works in practice, let's go with the simplest | |
// representation: a list of nodes. | |
// Each node has an inner value and a list of adjacent nodes it is connected to | |
// (through a directed edge). | |
// That list of adjacent nodes cannot be the exclusive owner of those nodes, or | |
// else each node would have at most one edge to another node and the graph | |
// couldn't also own these nodes. | |
// We need to wrap Node with a reference-counted box, such as Rc or Arc. We'll | |
// go with Rc, because this is a toy example. | |
// However, Rc<T> and Arc<T> enforce memory safety by only giving out shared | |
// (i.e., immutable) references to the wrapped object, and we need mutability to | |
// be able to connect nodes together. | |
// The solution for this problem is wrapping Node in either Cell or RefCell, to | |
// restore mutability. We're going to use RefCell because Node<T> doesn't | |
// implement Copy (we don't want to have independent copies of nodes!). | |
// Represents a reference to a node. | |
// This makes the code less repetitive to write and easier to read. | |
type NodeRef<T> = Rc<RefCell<InternalNode<T>>>; | |
// The private representation of a node. | |
struct InternalNode<T> { | |
inner_value: T, | |
adjacent: Vec<NodeRef<T>>, | |
} | |
// The public representation of a node, with some syntactic sugar. | |
struct Node<T>(NodeRef<T>); | |
impl<T> Node<T> { | |
// Creates a new node with no edges. | |
fn new(inner: T) -> Node<T> { | |
let node = InternalNode { | |
inner_value: inner, | |
adjacent: vec![], | |
}; | |
Node(Rc::new(RefCell::new(node))) | |
} | |
// Adds a directed edge from this node to other node. | |
fn add_adjacent(&self, other: &Node<T>) { | |
(self.0.borrow_mut()).adjacent.push(other.0.clone()); | |
} | |
} | |
struct Graph<T> { | |
nodes: Vec<Node<T>>, | |
} | |
impl<T> Graph<T> { | |
fn with_nodes(nodes: Vec<Node<T>>) -> Self { | |
Graph { nodes: nodes } | |
} | |
} | |
fn main() { | |
// Create some nodes | |
let node_1 = Node::new(1); | |
let node_2 = Node::new(2); | |
let node_3 = Node::new(3); | |
// Connect some of the nodes (with directed edges) | |
node_1.add_adjacent(&node_2); | |
node_1.add_adjacent(&node_3); | |
node_2.add_adjacent(&node_1); | |
node_3.add_adjacent(&node_1); | |
// Add nodes to graph | |
let graph = Graph::with_nodes(vec![node_1, node_2, node_3]); | |
// Show every node in the graph and list their neighbors | |
for node in graph.nodes.iter().map(|n| n.0.borrow()) { | |
let value = node.inner_value; | |
let neighbours = node.adjacent | |
.iter() | |
.map(|n| n.borrow().inner_value) | |
.collect::<Vec<_>>(); | |
println!("node ({}) is connected to: {:?}", value, neighbours); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment