first commit
This commit is contained in:
4
README.md
Normal file
4
README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Learning
|
||||
|
||||
Exploration a Rust Programming Language - (33 concepts)
|
||||
And ETC.
|
||||
1
Rust_Concepts/.gitignore
vendored
Normal file
1
Rust_Concepts/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
Rust_Concepts/Cargo.lock
generated
Normal file
7
Rust_Concepts/Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "Concepts"
|
||||
version = "0.1.0"
|
||||
22
Rust_Concepts/Cargo.toml
Normal file
22
Rust_Concepts/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "Concepts"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[[bin]]
|
||||
name = "Ownership" # the name you’ll use with --bin
|
||||
path = "src/ownership.rs" # path to the source file
|
||||
# cargo run --bin Ownership
|
||||
|
||||
[[bin]]
|
||||
name = "Borrowing" # the name you’ll use with --bin
|
||||
path = "src/borrowing.rs" # path to the source file
|
||||
# cargo run --bin Borrowing
|
||||
|
||||
|
||||
[[bin]]
|
||||
name = "MutBorrowing" # the name you’ll use with --bin
|
||||
path = "src/mutable_borrow.rs" # path to the source file
|
||||
# cargo run --bin MutBorrowing
|
||||
129
Rust_Concepts/src/borrowing.rs
Normal file
129
Rust_Concepts/src/borrowing.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
/* 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);
|
||||
|
||||
}
|
||||
3
Rust_Concepts/src/main.rs
Normal file
3
Rust_Concepts/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
|
||||
}
|
||||
98
Rust_Concepts/src/mutable_borrow.rs
Normal file
98
Rust_Concepts/src/mutable_borrow.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
/* Rust Concepts: https://sociocyber.site/rust_concepts_v2.html
|
||||
Concept: Mutable Borrow (&mut)
|
||||
Usage: change 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.
|
||||
---
|
||||
|
||||
For short:
|
||||
[Only one Reference] (&mut) --> (mut) [varaiable]
|
||||
ONLY Reference1 can modify mutable-variable1, not others refrences-N.
|
||||
ONLY ONE MUTABLE reference1 (&mut) ---> heap
|
||||
|
||||
|
||||
What this means?
|
||||
We can define mutable variable.
|
||||
And.. ONLY ONE reference for this mutable variable.
|
||||
Not two, not three, etc, ONLY ONE reference for ONE mut variable
|
||||
|
||||
We use this one reference to modify a varible value
|
||||
For this we need:
|
||||
1. Mutable variable - let mut var_name = value
|
||||
2. Reference to mutable variable - type: &mut
|
||||
|
||||
So, How to crate a reference for mutable variable?
|
||||
|
||||
1. Use type "mut" for variable.
|
||||
|
||||
### let mut variable = String::from("Value");
|
||||
|
||||
2. In expressions(in function calls, when save into new variable)
|
||||
|
||||
### Use a type "&mut".
|
||||
|
||||
This means a reference for mutable variable => i can change a value.
|
||||
let reference = &mut variable; <-- use "&mut [variable_name]".
|
||||
|
||||
|
||||
P.S. Never write a "mut &variable" => uncorrect! compile errors!
|
||||
|
||||
For function calls as argument:
|
||||
- add_word(&mut var_name);
|
||||
|
||||
If we want describe reference type of mutable variable
|
||||
in variables definitions, function calls,.
|
||||
|
||||
Then use this syntax:
|
||||
|
||||
1. let reference: &mut [TYPE] * let model: &mut String = ... ... ;
|
||||
2. function(argument1: &mut [TYPE]) * do_some_thing_with_value(&mut value);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* 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 add_word(first_word: &mut String, second_word: &mut String) {
|
||||
first_word.push_str(" ");
|
||||
first_word.push_str(second_word);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut arg1 = String::from("Notebook"); // mutable variable, holds a value in heap
|
||||
let mut arg2 = String::from("Model");
|
||||
let mut arg3 = String::from("1012");
|
||||
|
||||
// symbol '_' in '_reference1' means = disable compiler warnings for unusable variables now
|
||||
let _reference1: &mut String = &mut arg1; // Mutable Borrowing
|
||||
let _reference2: &mut String = &mut arg2; // Reference to mutable variable
|
||||
|
||||
// We can create reference for mutable (mut) variable and put into functions
|
||||
// add_word(reference1, reference2);
|
||||
|
||||
// We can use this syntax too.
|
||||
// "&mut arg1",. means a reference for mutable (mut) variable
|
||||
add_word(&mut arg1, &mut arg2);
|
||||
add_word(&mut arg1, &mut arg3);
|
||||
|
||||
// let _reference3: &mut String = &arg1; // ❌ can't borrow immutably while mut borrow active (but if type not setted, compile automaticaly set _reference3 as &mut)
|
||||
// println!("{}", _reference3); // expected mutable reference `&mut String` but found reference `&String`
|
||||
|
||||
println!("{}", arg1); // "Notebook Model 1012"
|
||||
}
|
||||
82
Rust_Concepts/src/ownership.rs
Normal file
82
Rust_Concepts/src/ownership.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
/* Rust Concepts: https://sociocyber.site/rust_concepts_v2.html
|
||||
Concept: Ownership
|
||||
|
||||
One value = One owner
|
||||
owner means -> who have something
|
||||
|
||||
Ownership means moves ptr1's address into ptr2 (this happens in stack)
|
||||
Moving structs from [stack-slots1] into [stack-slots2]
|
||||
|
||||
ptr - pointer (similar to pointer in C/C++)
|
||||
|
||||
Variable(owner) saved in scope, when runtime out of scope,
|
||||
then the value is freed automaticly from MEM. (no garbage collector)
|
||||
In rust garbage collector is not used. Borrwing & prevent
|
||||
|
||||
┌─────────────────────┐ ┌─────────────────────┐
|
||||
│ Stack – owner1 │ │ Stack – owner2 │
|
||||
│ (before move) │ │ (after move) │
|
||||
│ │ │ │
|
||||
│ +----------------+ │ │ +----------------+ │
|
||||
│ | ptr → heap "V" | │ move → │ | ptr → heap "V" | │
|
||||
│ | len = 5 | │ │ | len = 5 | │
|
||||
│ | cap = 5 | │ │ | cap = 5 | │
|
||||
│ +----------------+ │ │ +----------------+ │
|
||||
└─────────────────────┘ └─────────────────────┘
|
||||
|
||||
Heap (single allocation)
|
||||
┌───────────────────────────────────────┐
|
||||
│ 0xABCDEF00: V a l u e … │
|
||||
└───────────────────────────────────────┘
|
||||
|
||||
|
||||
|
||||
Scope ends → drop(owner2) → memory freed
|
||||
|
||||
Heap (single allocation - out of scope)
|
||||
┌───────────────────────────────────────┐
|
||||
│ 0xABCDEF00: … │
|
||||
└───────────────────────────────────────┘
|
||||
*/
|
||||
|
||||
|
||||
fn main() {
|
||||
let owner1 = String::from("Value"); // ? save "Value" in heap, stack (owner1) → ptr → heap "hello"
|
||||
/*
|
||||
stack-slots1
|
||||
+-------------------+ ← lower address (stack grows down)
|
||||
| ptr → heap "hello"| ← 8 bytes
|
||||
| len = 5 | ← 8 bytes
|
||||
| cap = 5 | ← 8 bytes
|
||||
+-------------------+ ← higher address
|
||||
|
||||
heap address (ptr) → [ 'h' 'e' 'l' 'l' 'o' ]
|
||||
*/
|
||||
|
||||
let owner2 = owner1; // owershipped! owner1 moves (ship) his value into owner1. stack (owner2) → ptr (getted from owner1) → heap "hello"
|
||||
|
||||
/*
|
||||
stack slot (owner2) ──► ptr → heap "hello"
|
||||
stack slot (owner1) ──► ptr <moved> // not can be used,
|
||||
|
||||
stack-slots2 stack-slots1
|
||||
owner2 (on stack) owner1 (on stack)
|
||||
+-------------------+ +-----------------------+
|
||||
| ptr → heap "hello"| | <ptr moved / invalid> |
|
||||
| len = 5 | + <len moved / invalid> +
|
||||
| cap = 5 | | <cap moved / invalid> |
|
||||
+-------------------+ +-----------------------+
|
||||
|
||||
heap address (ptr) → None (not valid)
|
||||
*/
|
||||
|
||||
// println!("{}", owner1); // owner1 no longer valid, not ptr. (Compiler thinks this about as 'None')
|
||||
// Not actual address for heap, where value
|
||||
|
||||
println!("(Ownership) owner1 -> owner2; owner2 = {}", owner2);
|
||||
} // owner2 Out of the scope, drops owner2 for free a heap
|
||||
|
||||
|
||||
// When owner2 and owner1 go out of scope, they will both try to free the same memory. This is known as a double free error and is one of the memory safety bugs we mentioned previously. Freeing memory twice can lead to memory corruption, which can potentially lead to security vulnerabilities.
|
||||
// To ensure memory safety, after the line let owner2 = owner1;, Rust considers owner1 as no longer valid.
|
||||
// Therefore, Rust doesn’t need to free anything when owner1 goes out of scope.
|
||||
Reference in New Issue
Block a user