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 9 of 50 · rust

Ownership Fundamentals

Duration: 15 minutes

Ownership Fundamentals\n\nOwnership is Rust's most defining feature—it enables memory safety without garbage collection. Understanding ownership is crucial to mastering Rust.\n\n## The Three Ownership Rules\n\n1. Each value has one owner\n2. You can transfer ownership (move)\n3. When the owner goes out of scope, the value is dropped\n\n## Basic Ownership\n\nrust\nfn main() {\n let s1 = String::from(\"hello\"); // s1 owns the String\n let s2 = s1; // Ownership moves to s2\n // println!(\"s1: {}\", s1); // ERROR! s1 no longer owns the data\n println!(\"s2: {}\", s2); // OK\n}\n\n\nWhen s2 = s1 executes, ownership transfers. s1 is no longer valid.\n\n## Stack vs Heap\n\nUnderstanding ownership requires knowing where data lives:\n\n### Stack\nFixed-size, fast, automatic cleanup. Stores simple types and references.\n\nrust\nlet x = 5; // Stack: integer\nlet y = x; // Stack: copies the value\nprintln!(\"x: {}, y: {}\", x, y); // Both valid (integers are Copy)\n\n\n### Heap\nVariable-size, allocated at runtime. Stores complex types.\n\nrust\nlet s = String::from(\"hello\"); // Data on heap, pointer on stack\n\n\n## Copy Types\n\nSimple types implement Copy, allowing implicit duplication:\n\nrust\nlet x = 5;\nlet y = x; // Copies the value (not move)\nprintln!(\"x: {}, y: {}\", x, y); // Both valid\n\n\nTypes that implement Copy: integers, floats, booleans, chars (and tuples of these).\n\n## Functions and Ownership\n\nPassing values to functions also transfers ownership:\n\nrust\nfn takes_ownership(s: String) {\n println!(\"{}\", s);\n} // s goes out of scope, String is dropped\n\nfn main() {\n let s = String::from(\"hello\");\n takes_ownership(s); // Ownership transferred\n // println!(\"s: {}\", s); // ERROR!\n}\n\n\n## Return Ownership\n\nFunctions can return ownership:\n\nrust\nfn return_string() -> String {\n String::from(\"hello\")\n}\n\nfn main() {\n let s = return_string(); // Ownership transferred to s\n println!(\"s: {}\", s); // OK\n}\n\n\n## Practical Example\n\nrust\nfn get_length(s: String) -> (String, usize) {\n let len = s.len();\n (s, len) // Return both String and its length\n}\n\nfn main() {\n let s = String::from(\"hello\");\n let (s, len) = get_length(s); // Reclaim ownership\n println!(\"The string '{}' has length {}\", s, len);\n}\n\n\nThis pattern is tedious—that's where borrowing comes in (next lesson).\n\n## Memory Safety Benefits\n\nOwnership prevents:\n- Use-after-free: Can't use freed memory\n- Double-free: Each value has one owner\n- Data races: Clear responsibility for cleanup\n\nThe compiler enforces all of this at compile time, with zero runtime cost.

Previous: FunctionsNext: Borrowing and References