[Avg. reading time: 4 minutes]
Borrowing
Borrowing allows you to access data without taking ownership.
Instead of moving a value, you pass a reference using &.
This prevents ownership transfer and keeps the original value usable.
Problem: Ownership Transfer
// This will fail fn printname(p_name: String) { println!("{p_name}"); } fn main() { let name = String::from("Rachel"); printname(name); printname(name); // error: value moved }
Why this fails?
- String does not implement Copy
- Ownership moves into printname
- name becomes invalid after first call
How to fix it?
Borrowing Concept
// Instead of passing the actual value, passing the Reference / Borrow operator fn printname(p_name:&String){ println!("{p_name}-Stack {:p}-> Heap {:p}",&p_name,p_name.as_ptr()) } // by default len() returns usize. fn get_length(p_name: &String) -> i8 { let name_length:i8 = p_name.len() as i8; name_length } fn main() { let name:String = String::from("Rachel"); printname(&name); printname(&name); let name_length = get_length(&name); println!("Length is {name_length}"); }
What changed:
- &String means “borrow”
- Ownership stays in main
- Multiple immutable borrows are allowed
- No data is copied
- No heap reallocation happens
Using String.clone()
// String.clone() fn printname(name:String){ println!("{},{:p},{:p}",name,&name,name.as_ptr()) } fn main() { let name:String = String::from("Rachel"); printname(name.clone()); printname(name.clone()); printname(name); }
What clone() does:
- Allocates new heap memory
- Copies the bytes
- Creates a completely independent value
Important:
- clone() is explicit and potentially expensive
- Borrowing is usually preferred
- Clone only when you need separate ownership