/* Rust Concepts: https://sociocyber.site/rust_concepts_v2.html Concept: Borrowing (shared &) Usage: read a value, without holding it. --- We call the action of creating a reference borrowing. As in real life, if a person owns something, you can borrow it from them. When you’re done, you have to give it back. You don’t own it. Ampersands '&' represent references, and they allow you to refer to some value without taking ownership of it. & to indicate of the parameter X is a reference. --- Owner1 in this context means who (stack frame) hold a data in heap [MEM area] Value can be shared to someone. & (reference) means = i want share this variable-value to someone We can reference to a variable for get,read his value. One variable can have many who want get his value. MANY readers and ONE value. Many & (references) to somethings. (many &refs allowed simultaneously) We can NOT change reference. We can NOT change value when want to read this. & (reference) = not changeble, only readable &owner1 means = reference to a variable for get his value. STACK (and his frames) [CPU] HEAP [MEM] ────────────────────────────────── ────────────────────── frame: main() ┌────────────────────┐ ┌──────────────────────────────┐ │ "Borrowing Value" │ │ owner1 : String │ owns │ 15 bytes, UTF-8 │ │ ┌──────────────────────────┐ │ ─────────► │ [B][o][r][r][o]... │ │ │ ptr │ │ └────────────────────┘ │ │ len = 15 │ │ │ │ cap = 15 │ │ │ └──────────────────────────┘ │ └──────────────────────────────┘ frame: print_len( &owner1 ) ┌──────────────────────────────┐ │ s : &String (borrow) │ │ ┌──────────────────────────┐ │ │ │ ptr ──► owner1 │ │ (read-only, no copy) │ └──────────────────────────┘ │ └──────────────────────────────┘ │ └─► borrow ends when print_len() returns frame: println!("{}", owner1) ┌──────────────────────────────┐ │ owner1 still valid │ │ println! auto-borrows &owner1│ │ no & needed in code │ └──────────────────────────────┘ */ /* Arguments in functions creates a new stack frame with pointer2 --> pointer1 --> Heap first address of "v a l u e" Like it: add_word(arg1: &String) &arg1 - new ptr -> ptr -> value */ fn print_len(string: &String) { // borrows println!("{}", string.len()); // Read reference (de-reference for get value) ptr2(&owner1) => get ptr1 (owner1) => read heap } fn main() { let owner1 = String::from("Borrowing Value"); // change_value(&owner1); // Not allowed! We can't change value only READ. print_len(&owner1); // borrowing, not ownership. Not change address in stack-slot for ptr (-> heap), make new ptr in stack (in new frame [ptr ──► owner1]) // ptr2 (reference1) -> ptr1 (owner1) -> heap ["Borrowing Value"] // ptr2 (reference2) -> ptr1 (owner1) -> heap ["Borrowing Value"] // ptr2 (reference3) -> ptr1 (owner1) -> heap ["Borrowing Value"] // ptr2 (&owner1) -> ptr1 (owner1) -> heap ["Borrowing Value"] println!("(Borrowing) {}", owner1); // not need reference. Why? /* STACK HEAP ────────────────────────────────── ────────────────────── frame: main() ┌────────────────────┐ ┌──────────────────────────────┐ │ "Borrowing Value" │ │ owner1 : String │ owns │ 15 bytes, UTF-8 │ │ ┌──────────────────────────┐ │ ─────────► │ [B][o][r][r][o]... │ │ │ ptr │ │ └────────────────────┘ │ │ len = 15 │ │ │ │ cap = 15 │ │ │ └──────────────────────────┘ │ │ │ │ reference1 : &String │ │ ┌──────────────────────────┐ │ │ │ ptr ──► owner1 (above) │ │ <── new slot in same frame │ └──────────────────────────┘ │ └──────────────────────────────┘ frame: print_len( reference1 ) ┌──────────────────────────────┐ │ s : &String (borrow) │ │ ┌──────────────────────────┐ │ │ │ ptr ──► reference1 │ │ (copy of the pointer, same address) │ └──────────────────────────┘ │ └──────────────────────────────┘ │ └─► borrow ends when print_len() returns reference1 still valid in main() owner1 still valid in main() */ let reference1 = &owner1; // save in new stack's slot in main frame a ptr to owner1 // let reference2 = &owner1; // let reference3 = &owner1; print_len(reference1); // print_len(reference2); // print_len(reference3); }