1. What is a Reference?
A reference in Rust is like a pointer in other languages, but with strict safety rules. It allows you
to access a value without taking ownership.
Example of a Reference
rust
CopyEdit
fn main() {
     let x = 10;
     let r = &x;        // `r` is a reference to `x`
     println!("Value of x: {}", r);
}
Here, r is a reference to x, meaning it does not own x but can read its value.
2. Immutable vs. Mutable References
Rust has two types of references:
    ● Immutable references (&T) → Read-only access.
    ● Mutable references (&mut T) → Read and write access.
Immutable Reference Example
rust
CopyEdit
fn main() {
     let x = 42;
     let r1 = &x;
     let r2 = &x;
     println!("r1: {}, r2: {}", r1, r2); // Both references are allowed
}
You can have multiple immutable references at the same time.
Mutable Reference Example
rust
CopyEdit
fn main() {
     let mut x = 42;
     let r = &mut x;        // Mutable reference
     *r += 1;      // Dereferencing and modifying x
     println!("Updated x: {}", r);
}
    ● &mut x means r is a mutable reference to x.
    ● *r dereferences the reference to modify x.
Rules of References
    1. You can have multiple immutable references OR one mutable reference, but not
        both at the same time.
    2. The reference must not outlive the value it refers to.
Violation Example (Won't Compile)
rust
CopyEdit
fn main() {
     let mut x = 10;
     let r1 = &x;       // Immutable reference
     let r2 = &mut x;        // Mutable reference (ERROR!)
     println!("{}", r1);
}
This fails because we cannot have a mutable reference while an immutable reference exists.
3. Dangling References
Rust prevents references from being used after the value they point to is dropped.
Dangling Reference Example (Won't Compile)
rust
CopyEdit
fn dangling_reference() -> &String {
     let s = String::from("Hello");
     &s   // ERROR! `s` will be dropped at the end of the function
}
Since s is dropped when the function ends, the reference would be invalid. Rust prevents this.
Solution: Return an Owned Value
rust
CopyEdit
fn safe_reference() -> String {
     let s = String::from("Hello");
     s    // Ownership is moved instead of referencing
}
4. Lifetimes and References
Lifetimes ensure references are valid as long as the borrowed value exists.
Example with Explicit Lifetime
rust
CopyEdit
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
     if s1.len() > s2.len() { s1 } else { s2 }
}
fn main() {
     let string1 = String::from("hello");
     let string2 = String::from("world!");
     let result = longest(&string1, &string2);
     println!("Longest: {}", result);
}
Here, 'a ensures that both s1 and s2 have the same lifetime, avoiding invalid references.
5. Reference in Structs
rust
CopyEdit
struct Person<'a> {
     name: &'a str,       // Reference with a lifetime
}
fn main() {
     let name = String::from("Alice");
     let person = Person { name: &name };
     println!("Person's name: {}", person.name);
}
The 'a lifetime ensures Person does not outlive name.
6. Smart Pointers and References
Rust also provides smart pointers like Box<T>, Rc<T>, and RefCell<T> to manage
ownership.
Example: Rc (Reference Counted Pointer)
rust
CopyEdit
use std::rc::Rc;
fn main() {
     let data = Rc::new(42);
     let ref1 = Rc::clone(&data);
     let ref2 = Rc::clone(&data);
     println!("Data: {}", ref1);
}
Rc<T> allows multiple references while managing ownership.
Summary
     Feature         Immutable Reference        Mutable Reference (&mut
                            (&T)                             T)
 Read value         ✅ Allowed                 ✅ Allowed
 Modify value       ❌ Not Allowed             ✅ Allowed
 Multiple at once   ✅ Allowed                 ❌ Only one at a time
 Mixed use          ❌ Not Allowed             ❌ Not Allowed