Theoretical Paper
- Computer Organization
- Data Structure
- Digital Electronics
- Object Oriented Programming
- Discrete Mathematics
- Graph Theory
- Operating Systems
- Software Engineering
- Computer Graphics
- Database Management System
- Operation Research
- Computer Networking
- Image Processing
- Internet Technologies
- Micro Processor
- E-Commerce & ERP
- Dart Programming
- Flutter Tutorial
- Numerical Methods Tutorials
- VueJS
- Go
Practical Paper
Industrial Training
Rust Rc(T)
-
The Rc< T> stands for Reference Counted Smart Pointer.
The Rc< T> smart pointer keeps track of the number of references to a value to determine whether the value is still in use or not and if there are zero references to a value, then the value can be cleaned up.
The Rc< T> smart pointer is a single threaded reference-counting pointer.
Using Rc< T> to share data
Let's create the two lists that share the ownership of a third list.
In the above figure, b and c are the two lists that share the ownership to the third list,a.
Let's implement the above scenario using Box< T> type.
enum List { Cons(i32, Box< List>), Nil, } use List::{Cons,Nil}; fn main() { let a = Cons(10, Box::new(Cons(15,Box::new(Nil)))); let b = Cons(2, Box::new(a)); let c = Cons(1, Box::new(a)); }
Output:
In the above example, cons variant consists of a data of type i32 and Box< T> pointing to a list. We create the list 'b' and the ownership of 'a' is moved to the 'b' list. Then, we try to move the' a' list to the 'c' list, but a list cannot be moved as 'a' list is already moved to the 'b' list.
How to overcome this problem
We can overcome this problem by changing the definition of the cons variant. Now, cons variant consists of a data that they hold and Rc< T> pointing to the List.
Let's see a simple example:
enum List { Cons(i32, Rc< List>), Nil, } use List::{Cons,Nil}; use std::rc::Rc; fn main() { let a = Rc::new(Cons(10, Rc::new(Cons(15,Rc::new(Nil))))); let b = Cons(2, Rc::clone(&a)); let c = Cons(1, Rc::clone(&a)); }
In the above example, we need to add the use statement to bring the Rc< T> into the scope. Instead of taking the ownership of a, we will clone the Rc< T> list that a is holding and, therefore increasing the number of references from one to two as now, a and b are sharing the ownership of the data in that Rc< List>. We will again clone the Rc< List> when creating the c List, therefore increasing the references from two to three.
Cloning an Rc< T> Increases the Reference Count
Now, we will see how Rc< T> increases or drops the reference count when the list goes out of the scope.
Let's see a simple example:
enum List { Cons(i32, Rc< List>), Nil, } use List::{Cons,Nil}; use std::rc::Rc; fn main() { let a = Rc::new(Cons(10, Rc::new(Cons(15,Rc::new(Nil))))); println!("Reference count after creating a List : {}", Rc::strong_count(&a)); let b = Cons(2, Rc::clone(&a)); println!("Reference count after creating b List : {}", Rc::strong_count(&a)); { let c = Cons(1, Rc::clone(&a)); println!("Reference count after creating c List : {}",Rc::strong_count(&a)); } println!("Reference count when c goes out of the scope : {}",Rc::strong_count(&a)); }
Output:
Reference count after creating a List : 1 Reference count after creating b List : 2 Reference count after creating c List : 3 Reference count when c goes out of the scope : 2
In the above example, we print the reference count by calling the Rc::strong_count function. An initial reference count of a in Rc< List> is 1 and when we call clone, then the reference count increases by 1. If variable goes out of the scope, then the reference count decreases by 1. Therefore, we can say that the Drop trait automatically decreases the reference count when an Rc< T>/ value goes out of the scope.