create account

Rust lang series episode #28 — linking data structures (#rust-series) by jimmco

View this thread on: hive.blogpeakd.comecency.com
· @jimmco · (edited)
Rust lang series episode #28 — linking data structures (#rust-series)
![](https://ipfs.pics/ipfs/QmRewcCALeid2GMkjouKTcYcTwVoJ4XcfrxnUjMQ55q25L)

Hello everyone, new [Rust lang series](https://steemit.com/created/rust-series) episode is here. Today we will play with references and composing data across structures or simply said with linking data structures. 

In the past we've used  **Article** struct that describes an article with basic properties. Imagine you have multiple structs which you want to reference each other. For example, article is written just by one user which makes it relation one-to-one. Second case would be an user writing multiple articles. That gives us one-to-many relation. Today we will try to implement these relations in Rust.

We will utilize this new API:
* std::rc::Rc
* std::rc::Weak
* std::cell::RefCell

## Simple unidirectional reference
Let's start with a one-to-one situation we want to have **Article** that has reference to User. Check the code first and we will break it down jut after that. 

```rust
use std::rc::Rc;

#[derive(Debug)]
struct User {
    username: String,
    email: String,
}

#[derive(Debug)]
struct Article {
    id: i32,
    upvotes: i32,
    author: Rc<User>
}


fn main() {
    let u1: Rc<User> = Rc::new(User {
        username: "dan".to_string(),
        email: "dan@domain.com".to_string()
    });
    let u2: Rc<User> = Rc::new(User {
        username: "ned".to_string(),
        email: "ned@domain.com".to_string()
    });

    let a1 = Article{id:1, upvotes: 10, author: u1.clone() };
    let a2 = Article{id:2, upvotes: 20, author: u1.clone() };
    let a3 = Article{id:3, upvotes: 30, author: u2.clone() };

    println!("{:?}", a1);
    println!("{:?}", a2);
    println!("{:?}", a3);
```

### Output
```
Article { id: 1, upvotes: 10, author: User { username: "dan", email: "dan@domain.com" } }
Article { id: 2, upvotes: 20, author: User { username: "dan", email: "dan@domain.com" } }
Article { id: 3, upvotes: 30, author: User { username: "ned", email: "ned@domain.com" } }
```

## Breaking down
Reference counted boxes **Rc** can be created with:

```
let counted_reference = Rc::new(variable);
```

 When we have defined a countable reference type we can copy this reference (clone it)  whenever we want by using **clone()** method. 

```
let counted_reference2 = counted_refernce.clone();
let counted_reference3 = counted_refernce.clone();
let counted_reference4 = counted_reference.clone();
```
Besides that there is nothing special needed for our needs. It basically means that when a new reference clone is created, counter is increased. Why we need Rc at all? Because we need to provide multiple ownership for User value and Rc provides handy and guaranteed way how to do it. 


## Bidirectional references
Now let's take a look at more complex example where we want to also keep reference to all articles written by a User. We cannot achieve that just with **Rc** because it would bring cycle to our references. We need some other types like **Weak** and **RefCell** to achieve this goal. **Weak** will provide weak pointer that will not be counted as a new reference and **RefCell** will provide mutability for our vector. First take a look at the code and we will break it down below to explain new things.

```rust
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;

struct User {
    username: String,
    email: String,
    articles: RefCell<Vec<Weak<Article>>>
}

struct Article {
    id: i32,
    upvotes: i32,
    author: Rc<User>
}

fn main() {
    // defining users
    let u1 = User {
        username: "dan".to_string(),
        email: "dan@domain.com".to_string(),
        articles: RefCell::new(Vec::new())
    };

    let u2 = User {
        username: "ned".to_string(),
        email: "ned@domain.com".to_string(),
        articles: RefCell::new(Vec::new())
    };

    // defining users counted references
    let u1_rc: Rc<User> = Rc::new(u1);
    let u2_rc: Rc<User> = Rc::new(u2);

    // defining articles
    let a1 = Article { id: 1, upvotes: 0, author: u1_rc.clone() };
    let a2 = Article { id: 2, upvotes: 0, author: u1_rc.clone() };
    let a3 = Article { id: 2, upvotes: 0, author: u2_rc.clone() };

    // defining article counted references
    let a1_rc = Rc::new(a1);
    let a2_rc = Rc::new(a2);
    let a3_rc = Rc::new(a3);

    // pushing article references to users
    u1_rc.articles.borrow_mut().push(Rc::downgrade(&a1_rc));
    u1_rc.articles.borrow_mut().push(Rc::downgrade(&a2_rc));
    u2_rc.articles.borrow_mut().push(Rc::downgrade(&a3_rc));

    for article in u1_rc.articles.borrow().iter() {
        let a = article.upgrade().unwrap();
        println!("Article with ID: {} written by {}", a.id, a.author.username);
    }
```

### Output
``` rust
Article with ID: 1 written by dan
Article with ID: 2 written by dan
```

## Breaking down
Let's break it down and summarize a bit:

**RefCell** provides mutable reference over the wrapped object, in our case vector of articles

**Weak** provides weak pointer that wee need to avoid memory leaks and cycles for bi-directional referencing. 

**downgrade()** method returns **Weak** non-owning pointer from **Rc**

**upgrade()** method returns **Rc** reference from **Weak** reference.  We cannot work directly with Weak because it doesn't guarantee that data are still valid. For simplicity I've used unwrap() but you should consider better error handling.  

**borrow_mut()** method mutably borrows the wrapped value of **RefMut**

Like this you can compose your data structures. Note that this will work in single-threaded environment. For multi-threaded approach we will take a look in the future.

## Postfix

That's all for now, thank you for your appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). May Jesus bless your programming skills, use them wisely and see you next time.

Meanwhile you can also check the official documentation for more related information:
* https://doc.rust-lang.org/std/rc/struct.Rc.html
* https://doc.rust-lang.org/std/rc/struct.Weak.html
* https://doc.rust-lang.org/std/cell/struct.RefCell.html

[#rust-series](https://steemit.com/created/rust-series)
[#rust-lang](https://steemit.com/created/rust-lang)
[#rust](https://steemit.com/created/rust)
👍  , , , , , , , , , , , , , , , , , , ,
properties (23)
authorjimmco
permlinkrust-lang-series-episode-28-linking-data-structures-rust-series
categoryrust-series
json_metadata{"tags":["rust-series","rust-lang","rust","programming","linking-data"],"image":["https://ipfs.pics/ipfs/QmRewcCALeid2GMkjouKTcYcTwVoJ4XcfrxnUjMQ55q25L"],"links":["https://steemit.com/created/rust-series","https://doc.rust-lang.org/std/rc/struct.Rc.html","https://doc.rust-lang.org/std/rc/struct.Weak.html","https://doc.rust-lang.org/std/cell/struct.RefCell.html","https://steemit.com/created/rust-lang","https://steemit.com/created/rust"]}
created2016-10-25 13:26:06
last_update2016-10-26 08:04:18
depth0
children1
last_payout2016-11-25 14:13:36
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length6,269
author_reputation9,585,502,514,260
root_title"Rust lang series episode #28 — linking data structures (#rust-series)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id1,617,069
net_rshares169,060,972,745
author_curate_reward""
vote details (20)
@matthewdavid ·
Thanks for these #rust-lang articles. I'm interested in Rust and plan on studying it in the near future. Right now I'm focusing on Javascript.

Have you used the [rocket](https://rocket.rs/) web framework written in Rust? I saw that and it looked really good. Once I've gotten more of a base in programming principles, I'd really like to experiment with rocket.rs
properties (22)
authormatthewdavid
permlinkre-jimmco-rust-lang-series-episode-28-linking-data-structures-rust-series-20170724t070944083z
categoryrust-series
json_metadata{"tags":["rust-lang","rust-series"],"links":["https://rocket.rs/"],"app":"steemit/0.1"}
created2017-07-24 07:09:42
last_update2017-07-24 07:09:42
depth1
children0
last_payout2017-07-31 07:09:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length363
author_reputation2,155,255,892,877
root_title"Rust lang series episode #28 — linking data structures (#rust-series)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id9,501,867
net_rshares0