Skip to main content
Brave Programmer Logo

BraveProgrammer

BraveProgrammer

HomeProjectsBlogsCoursesLessonsAbout

Site footer

BraveProgrammer

Free coding courses, practical tutorials, and real projects from BraveProgrammer. Learn web development with React, Next.js, and TypeScript.

Navigation

  • Home
  • Projects
  • Blogs
  • Courses

Resources

  • About
  • Lessons

© 2026 BraveProgrammer. All rights reserved.

  1. Courses
  2. /
  3. Rust Fundamentals

Lesson 10 of 50 · rust

Borrowing and References

Duration: 15 minutes

Borrowing and References\n\nBorrowing lets you reference values without taking ownership. This is one of Rust's most powerful features, enabling flexible yet safe code.\n\n## Immutable References\n\n&T allows you to read a value without ownership:\n\nrust\nfn calculate_length(s: &String) -> usize {\n s.len()\n} // s goes out of scope, but it doesn't own the String, so nothing is dropped\n\nfn main() {\n let s = String::from(\"hello\");\n let len = calculate_length(&s); // Pass reference, not ownership\n println!(\"The length of '{}' is {}\", s, len); // s is still valid!\n}\n\n\nThe reference lets the function read the data without taking ownership. After the function returns, the original owner still has the value.\n\n## Mutable References\n\n&mut T allows reading AND writing:\n\nrust\nfn append_world(s: &mut String) {\n s.push_str(\" world\");\n}\n\nfn main() {\n let mut s = String::from(\"hello\");\n append_world(&mut s); // Pass mutable reference\n println!(\"{}\", s); // \"hello world\"\n}\n\n\nMutable references give temporary write permission while the original owner retains ultimate ownership.\n\n## The Borrowing Rules\n\nRust enforces strict borrowing rules at compile time to prevent data races:\n\n### Rule 1: Multiple Immutable References\n\nYou can have multiple read-only references:\n\nrust\nfn main() {\n let s = String::from(\"hello\");\n let r1 = &s; // First reference\n let r2 = &s; // Second reference\n let r3 = &s; // Third reference\n println!(\"r1: {}, r2: {}, r3: {}\", r1, r2, r3); // All OK\n}\n\n\n### Rule 2: Only One Mutable Reference\n\nAt any time, you can have ONE mutable reference OR multiple immutable references, but not both:\n\nrust\nfn main() {\n let mut s = String::from(\"hello\");\n let r1 = &s; // Immutable reference\n let r2 = &s; // Another immutable\n // let m = &mut s; // ERROR! Can't have mutable while immutable refs exist\n println!(\"r1: {}, r2: {}\", r1, r2);\n}\n\n\n### Why This Rule?\n\nThis prevents data races. Consider this scenario in other languages:\n\nrust\n// Hypothetically without borrowing rules\nlet mut data = 10;\nlet ref1 = &data; // Reference\n// ... if another thread modifies data ...\ndata = 20;\nprintln!(\"ref1: {}\", ref1); // Undefined behavior!\n\n\nRust's rules prevent this at compile time.\n\n## Reference Scope\n\nReferences go out of scope when they're last used, not when declared:\n\nrust\nfn main() {\n let mut s = String::from(\"hello\");\n let r1 = &s;\n let r2 = &s;\n println!(\"r1: {}, r2: {}\", r1, r2); // Last use of r1 and r2\n \n // r1 and r2 are out of scope here\n let m = &mut s; // OK! No immutable refs in scope\n println!(\"m: {}\", m);\n}\n\n\n## Practical Example\n\nrust\nfn check_contains(text: &String, word: &str) -> bool {\n text.contains(word)\n}\n\nfn make_uppercase(text: &mut String) {\n *text = text.to_uppercase();\n}\n\nfn main() {\n let mut message = String::from(\"hello rust\");\n \n // Immutable borrow\n if check_contains(&message, \"rust\") {\n println!(\"Found rust!\");\n }\n \n // Mutable borrow\n make_uppercase(&mut message);\n println!(\"Message: {}\", message);\n}\n\n\n## Key Benefits\n\n1. No copies: References avoid expensive data duplication\n2. Memory safe: Compiler prevents use-after-free\n3. No garbage collector: Deterministic cleanup\n4. Zero-cost: References compile to pointers, no runtime overhead

Previous: Ownership FundamentalsNext: Slices