> For the complete documentation index, see [llms.txt](https://thomasbui.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thomasbui.gitbook.io/blog/software-engineering/rust-101/smart-pointer/rc-less-than-t-greater-than.md).

# Rc\<T>

## What is the `Rc<T>` - Reference-counted Smart Pointer?

{% hint style="success" %}
💡 `Rc<T>` stands for **reference-counted** smart pointer that enables multiple ownership of the same data of type `T`. It provides a way to share **ownership** between different parts of a program without copying the data itself and keeps track of the number of **references** to a value, and the value is **deallocated** only when the reference count drops to **zero**.
{% endhint %}

Unlike regular references (`&T`) which can only have one owner, `Rc<T>` allows multiple owners to own the same data. This is useful when you need to share data between different parts of your program without transferring ownership and avoid duplication when the data needs to be accessed from multiple locations.

`Rc<T>` maintains a reference count, which keeps track of how many `Rc` instances point to the same value. When the last `Rc` pointing to the value goes out of scope, the value is automatically deallocated, preventing memory leak.

`Rc<T>` only allows immutable references to the data it wraps. If you need to mutate the data, you should use `RefCell<T>` in combination with `Rc<T>` to achieve interior mutability.

## Using `Box<T>` To Share Ownership

In this example, we’re building a `Cache` for memoizing the data that allows other services to use it for their memoization.

```rust
struct Cache {}

struct UserService {
    cache: Cache,
}

struct PostService {
    cache: Cache,
}

fn main() {
    // Create a shared cache
    let cache = Cache {};

    // Create UserService and PostService with the shared cache
    let user_service = UserService { cache: cache };
    let post_service = PostService { cache: cache }; // Error occurs here
}

```

We define a simple struct named `Cache`. It doesn't have any fields.

We define two structs `UserService` and `PostService`, each containing a single field named `cache` of type `Cache`.

In the main function, we create an instance of `Cache` and assign it to the variable cache.

We initialize an instance of `UserService` with the cache instance. Here, the ownership of the cache instance is moved to `user_service.cache`.

In the next line, we initialize an instance of `PostService` with the cache instance. The code attempts to move the `cache` instance again into `post_service.cache`, but `cache` has already been moved into `user_service.cache`, and Rust enforces single ownership of values by default, therefore, the error occurs.

The problem here is:

* **Move Semantics**: In Rust, when you assign or pass a value to another variable or function, the ownership of that value is transferred (moved). After a move, the original variable can no longer be used.
* **Ownership Rules**: Since `cache` is moved into `user_service`, it can no longer be used to create `post_service`. Attempting to use `cache` after it has been moved results in a compilation error because `cache` no longer owns the `Cache` instance.

To share the `Cache` instance between `UserService` and `PostService`, you need to use reference-counted smart pointers (`Rc<T>`) to allow multiple ownership.

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

#[derive(Debug)]
struct Cache {}

impl Cache {
    fn cache_data(&self) {
        println!("Cache the data")
    }
}

struct UserService {
    cache: Rc<Cache>,
}

struct PostService {
    cache: Rc<Cache>,
}

impl UserService {
    fn cache_data(&self) {
        self.cache.cache_data();
    }
}

impl PostService {
    fn cache_data(&self) {
        self.cache.cache_data();
    }
}

fn main() {
    // Create a shared cache
    let cache = Rc::new(Cache {});

    // Create UserService and PostService with the shared cache
    let user_service = UserService {
        cache: Rc::clone(&cache),
    };
    let post_service = PostService {
        cache: Rc::clone(&cache),
    };

    // Call cache_data function through UserService & PostService
    user_service.cache_data();
    post_service.cache_data();
}
```

In this code, we wrap the `Cache` instance inside both the `UserService` and `PostService` using `Rc` smart pointer. This means they share ownership of a single `Cache` instance.

We also implement a `cache_data` method that simply returns a string "Cache the data" (presumably a placeholder for actual caching logic).

In the main function, we create a `Cache` instance and wrap it in `Rc::new(Cache {})` to enable reference counting.

Two services, `user_service` and `post_service`, are created. They both receive a cloned reference (`Rc::clone(&cache)`) to the shared cache. By cloning the `Rc<Cache>`, you create additional references to the same `Cache` instance. This allows both `UserService` and `PostService` to own and use the same `Cache` instance.

When we clone an `Rc`, it increments a reference count instead of copying the actual value.

Finally, `cache_data` methods are called on both services. Since they share the same cache instance, both calls will ultimately execute the `cache_data` method defined in the `Cache` struct, potentially printing "Cache the data" twice.

### **How Rc executes the reference count of the Cache instance:**

1. Initially, the reference count of the `Cache` instance is 1 when it's wrapped in `Rc::new(Cache {})`.
2. When `user_service` and `post_service` are created, they both clone the existing `Rc<Cache>`, incrementing the reference count to 2.
3. Since both services share the same `Rc<Cache>`, they are essentially pointing to the same underlying `Cache` instance.
4. When `main` goes out of scope, both `user_service` and `post_service` will also eventually go out of scope.
5. As each `Rc<Cache>` in these services goes out of scope, the reference count is decremented by 1 (once for each service).
6. If there are no other owners of the `Cache` instance, the reference count will finally reach zero, and the `Cache` instance will be deallocated.
