📚
Open Polkadot Bootcamp
  • 📚 About the Bootcamp
    • 📖 Additional Resources
    • 👐 Ask For Support
  • 📖 Curriculum
  • 📕Rust Programming Language
    • Basic Rust
      • Introduction to Rust
        • 🧑‍💻 Excercises
      • Common Programming Concepts
        • 🧑‍💻 Excercises
      • Program Life Cycle
        • 🧑‍💻 Excercises
      • Ownership & Borrow Checker
      • Common Data Structures
    • Advanced Rust
      • Generic types, Trait extension and Advanced types
      • Lifetime Notation
      • Smart pointers & Macros
      • Common design patterns in Rust
      • Package management & How to structure your Rust project
      • Overview of the Rust ecosystem
  • 📘Building a blockchain with Polkadot SDK
    • Polkadot
      • Additional Reads
        • Why do you want to build a blockchain on Polkadot?
        • Understanding the sharded network design of Polkadot
      • Development on Polkadot
    • Polkadot SDK
      • Substrate
        • Create a new blockchain
          • 🧑‍💻 Exercise: Clone the minimal template
          • Understanding the architecture
          • Break down the node architecture
          • Introducing to Pop CLI tool
        • Adding a custom logic to runtime
          • 🧑‍💻 Exercise: Rust State Machine
          • Components of a Pallet
          • Hooks
          • Weights & Benchmarking
          • Extensions
            • Signed Extensions
            • Transaction Extensions
        • Common runtime modules
          • 📕Example: System Pallet
          • 📕Example: Contracts Pallet
          • 📕Example: Assets Pallet
          • 📕Example: Utility Pallet
        • Runtime API and RPC
        • Runtime upgrade
        • Bump Polkadot SDK versions
      • Cumulus
        • Introduction to Cumulus
          • Parachain from scratch
          • 🧑‍💻 Exercise: Build a parachain from scratch
        • Running a local relaychain network
          • Register & reserve a parachain
          • Launch the network & run a collator node
          • Launch the network with Pop CLI
        • Agile Coretime
    • Polkadot Hub
  • 📒Smart Contract Development
    • Introduction
      • Introduction to PolkaVM
      • Getting started with Solidity development
      • Solidity File Structure
      • Contract Structure
    • Basic Solidity
      • Value types
      • Reference Types
      • Mapping Types
      • Simple Storage
    • Advanced Solidity
      • Units
      • Global Variables
      • Expression and Control Structures
      • Advanced Storage
      • Contract Tests
      • Contracts
Powered by GitBook
On this page
  1. Rust Programming Language
  2. Basic Rust

Ownership & Borrow Checker

Previous🧑‍💻 ExcercisesNextCommon Data Structures

Last updated 7 months ago

Ownership in Rust could be a hard topic to understand and apply it in real code. Hence, let’s imagine Rust ownership using toys!

Imagine you have a toy car. In Rust, only one person can own that toy car at a time. This means only one person can hold it, play with it, and take care of it.

  1. Ownership Rule: If you give your toy car to your friend, now they are the owner, not you. You can't play with it anymore unless they give it back. This way, there's only ever one owner at a time—this prevents anyone from accidentally breaking it by both trying to use it at once.

  2. Borrowing Rule: Now, let's say you want to let your friend borrow your toy for a while without giving it to them completely. You can say, "Here, you can play with my toy, but I still own it." In Rust, this is called "borrowing." Your friend can play with the toy, but they know it still belongs to you and has to give it back soon. This keeps the toy safe because it always has one true owner.

  3. No Double-Owners Rule: Lastly, only one person can borrow the toy at a time to make sure it doesn’t get mixed up or broken. But if everyone just wants to look at the toy without touching it, several friends can peek at it at the same time. In Rust, these are called "immutable references."

So, Rust's ownership is like toy rules: only one owner, borrowing is temporary, and no fighting over the toy!

Let's be more specific

1. Moving Ownership

Imagine you’re holding your toy car, and you decide to give it to your friend Sam. When you hand the toy over, you’re not just sharing—you’re transferring full ownership to Sam. Now, only Sam can play with that toy, and you can’t touch it anymore. In Rust, we call this “moving” ownership. It’s like saying, “Hey, Sam, this toy car is yours now. I’ll get my own toy.”

fn main() {
    let toy = String::from("Toy car"); // `toy` owns the string

    let new_owner = toy; // `toy` is moved to `new_owner`

    // println!("{}", toy); // Error! `toy` no longer owns the value
    println!("{}", new_owner); // This works since `new_owner` is the current owner
}

2. Borrowing Mutably (or with Permission to Change)

Now, let’s say you’ve kept your toy car but let your friend Jamie borrow it. Jamie asks if they can change it by adding cool stickers. You decide, "Okay, but remember, I still own it!" In Rust, this is a mutable borrow. Jamie can make changes, but only because you allowed it temporarily. Once Jamie is done, they give it back, and you have your newly decorated toy car.

In Rust, you can only let one person at a time make changes with a mutable borrow. This ensures that there’s no confusion or conflict over who is modifying the toy.

fn main() {
    let mut toy = String::from("Toy car");

    // `toy` is borrowed mutably by `decorate`
    decorate(&mut toy); 

    println!("{}", toy); // Prints: "Toy car with stickers"
}

fn decorate(toy: &mut String) {
    toy.push_str(" with stickers"); // Modify the borrowed `toy`
}

3. Borrowing Immutably (Just to Look)

Now, let’s say a few of your friends just want to look at the toy, not play with it or add stickers. They ask, and you say, “Sure, you can all look at it, but don’t touch or change anything!” This is called an immutable borrow. You can let multiple friends look at it at once because they’re not changing anything. In Rust, this allows for several immutable borrows at the same time.

fn main() {
    let toy = String::from("Toy car");

    let look1 = &toy; // Immutable borrow
    let look2 = &toy; // Another immutable borrow

    println!("Look 1: {}", look1); // Prints: "Look 1: Toy car"
    println!("Look 2: {}", look2); // Prints: "Look 2: Toy car"

    // `toy.push_str(" new")`; // Error! Cannot modify `toy` while it is immutably borrowed
}

4. When the Toy Goes Out of Scope (Cleaning Up)

Finally, imagine it’s the end of the day, and you have to go home. You take your toy car with you, but if you forget it at your friend’s house, their parent might pick it up and put it away. In Rust, this is like when a value goes out of scope. When you’re done with a variable (or toy), Rust automatically “cleans it up” for you so there’s no leftover mess.

In programming terms, this cleanup is called dropping, and Rust does it automatically when the toy (or variable) is no longer needed.

fn main() {
    let toy = String::from("Toy car"); // `toy` owns the string
    {
        let _borrowed_toy = &toy; // `_borrowed_toy` borrows `toy`
        println!("Inside scope: {}", _borrowed_toy); // Works within this inner scope
    } // `_borrowed_toy` goes out of scope here

    println!("Outside scope: {}", toy); // Still accessible since `toy` is still in scope
} // `toy` goes out of scope and is automatically cleaned up
📕
Module 1.3 - Ownership & Borrow Checker
Logo
Above image gives you a visualization of how the pointer is moved and referenced which is a part of ownership.