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