Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Rust Ownership Model and Function Parameters

Tech May 14 1

Memory Storage and Variable Assignment

Rust manages memory through two primary storage areas:

  • Stack: Stores data with known size at compile time. This includes primitive types like integers, floats, booleans, characters, and tuples containing only these types. Stack follows FILO (First In, Last Out) principle.
  • Heap: Stores data with dynamic size determined at runtime, such as String objects.

Stack Variable Assignment

When assigning stack variables, data is simply copied:

let x = 42;
let y = x; // Creates a copy of the value

Heap Variable Assignment

Heap variables store pointers to memory locations. Assignment transefrs ownership rather than copying data.

Ownership Principles and Design Goals

Rust's ownership system addresses memory safety with out garbage collection by enforcing these rules:

  1. Every value must have an owner
  2. Only one owner per value at any given time
  3. Value is automatically deallocated when owner goes out of scope

This design ensures memory safety while maintaining performance suitable for systems programming.

Scope-Based Management

Ownership rules are enforced through well-defined scopes:

fn example() {
    let message = String::from("Hello World");
    println!("{}", message);
    // message is automatically dropped here
}

Moving vs Copying

When heap-allocated values are assigned, ownership moves:

let first = String::from("data");
let second = first;
// println!("{}", first); // This would cause a compile error

Types implementing the Copy trait bypass this behavior:

#[derive(Debug, Copy, Clone)]
enum ChickenType {
    FreeRange,
    BarnRaised,
    Organic,
}

#[derive(Copy, Clone, Debug)]
struct Egg {
    weight: u8,
    category: ChickenType,
}

fn main() {
    let egg1 = Egg { weight: 50, category: ChickenType::FreeRange };
    let egg2 = egg1; // Copy occurs due to Copy trait
    println!("{:?} {:?}", egg1, egg2); // Both accessible
}

Borrowing Solutions

To avoid ownership transfer complications, Rust provides borrowing mechanisms:

Immutable References

fn main() {
    let text = String::from("Reference Example");
    display(&text); // Borrow without transferring ownership
    display(&text); // Can borrow multiple times
    let ref1 = &text;
    let ref2 = &text;
    println!("{} {}", ref1, ref2);
}

fn display(content: &String) {
    println!("{}", content);
}

Mutable References

fn modify_text() {
    let mut data = String::from("Initial");
    let modifier = &mut data;
    modifier.push_str(" - Modified");
    
    let another_modifier = &mut data;
    another_modifier.push_str(" - Again");
    // println!("{}", modifier); // Would cause compile error
}

Slice References

fn string_slices() {
    let phrase = String::from("Hello World Example");
    let part1 = &phrase[0..5];
    let part2 = &phrase[6..11];
    println!("{} {}", part1, part2);
}

fn array_slices() {
    let mut nums = [10, 20, 30, 40, 50];
    let section: &mut [i32] = &mut nums[1..3];
    section[0] = 99;
    println!("{:?}", nums); // [10, 99, 30, 40, 50]
}

Function Parameter Behavior

Parameter passing follows ownership rules unless types implement Copy:

use std::ops::{Add, Sub};

#[derive(Debug, Copy, Clone)]
struct Coordinate {
    x: i32,
    y: i32,
}

impl Add for Coordinate {
    type Output = Coordinate;
    
    fn add(self, other: Coordinate) -> Coordinate {
        Coordinate {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl Sub for Coordinate {
    type Output = Coordinate;
    
    fn sub(self, other: Coordinate) -> Coordinate {
        Coordinate {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

fn main() {
    let point1 = Coordinate { x: 5, y: 10 };
    let point2 = Coordinate { x: 15, y: 20 };
    
    let sum = point1 + point2;
    let difference = point1 - point2;
    
    // Original values still accessible due to Copy trait
    println!("{:?} + {:?} = {:?}", point1, point2, sum);
    println!("{:?} - {:?} = {:?}", point1, point2, difference);
}

Key Concepts Summary

  • Rust's ownership model unique ensures memory safety without garbage collection
  • The three core ownership rules form the foundation for safe memory management
  • Borrowing mechanisms enable efficient resource sharing while maintaining safety
  • Types implementing Copy trait behave differently in assignments and function calls
  • Compiler enforces ownership rules at compile time, preventing runtime errors

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.