Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
others operating systems use this link
Cargo is the package manager for the rust. A rust uses cargo create a project.
cargo new learn-rust
This will create folder named learn-run containg a basic setup to run a rust project.
lean-rust/ ├── Cargo.lock ├── Cargo.toml ├── src │ └── main.rs
The main.rs will have a hello-world program.
To run the project
cargo run
- To print data to the standard output, with a newline.
println!("Hello"); // => "Hello"
println!("Hello, {}!", "world"); // => "Hello, world!"
println!("The number is {}", 1); // => "The number is 1"
println!("{:?}", (3, 4)); // => "(3, 4)"
println!("{value}", value=4); // => "4"
println!("{name} {}", 1, name = 2); // => "2 1"
println!("{b} {c} {b}", a="a", b='b', c=3); // => "a 3 b"
println!("{} {}", 1, 2); // => "1 2"
println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2"
println!("{:04}", 52); // => "0052" with leading zeros
println!("{:03}", 52); // => "052" with leading zeros
println!("{:03}", 521); // => "521"
println!("{:03}", 5213); // => "5213"
• Variables are by default immutable
let x = 5;
x = 6; // This will raise an error
println!("The value of x is {}", x);
• You can make a variable immutable by adding a 'mut' keyword in front of it.
let mut x = 5;
x = 6;
x -= 2;
println!("The value of x is {}", x);
• To make a constant use the 'const' keyword. In rust, constant variables must be an explicitly typed.
const SITE_ID: u32 = 7;
println!("The value of x is {}", SITE_ID);
• Shadowing in rust means making a new variable using the older name without mutating the first one. One must always use 'let' keyword when shadowing a variable.
let x = 2;
let x = x + 2;
let x = x * 2;
println!("x = {}", x);
let x = "Joe";
println!("x = {}", x);
- Scalar
- Compound
Numbers without fraction.
Unsigned Integers Can store all positive numbers.
Type | Minimum value | Maximum value |
---|---|---|
u8 | 0 | 2^8^-1 |
u16 | 0 | 2^16^-1 |
u32 | 0 | 2^32^-1 |
u64 | 0 | 2^64^-1 |
u128 | 0 | 2^128^-1 |
Signed Integers Can store all positive and negative numbers.
Type | Minimum value | Maximum value |
---|---|---|
i8 | -(2^7^) | 2^7^-1 |
i16 | -(2^15^) | 2^15^-1 |
i32 | -(2^31^) | 2^31^-1 |
i64 | -(2^63^) | 2^63^-1 |
i128 | -(2^127^) | 2^127^-1 |
let x: u8 = 120;
println!("x = {}", x);
let y = 61788565; // y is of u32 bcoz its the default type.
println!("y = {}", y);
let z = -20; // i8
println!("z = {}", z)
Numbers with fraction. f32 - 32 bits f64 - 64 bits, f64 is the default type.
let x = 3.14 // f64 bcoz its the default type.
let y: f32 = 3.14 // f32
Are of 1 byte in size.
let x: bool = false;
let y = true;
- Are unicoded code.
- Take up four bytes.
- Must use single quotes.
let x: char = 'J';
println!("x = {}", x);
- Immutable type with fixed length.
- Can hold elements of different type.
- Cannot change the element value after creation.
let data: (char, i8, f64) = ('A', -2, 3.14);
// Access tuple elements using period(.) symbol
println!("data.0 = {}", data.0);
println!("data.1 = {}", data.1);
println!("data.2 = {}", data.2);
let data = (1, 'a', false);
println!("{:?}", data)
let (x, y, z) = data; // This is called destructuring.
println!("x = {}", x);
println!("y = {}", y);
println!("z = {}", z);
- Immutable type with fixed length.
- Can hold only elements of same type.
- Cannot change the element value after creation.
// [i8; 3] Here i8 is the type and 3 is length of the array;
let arr: [i8; 3] = [101, 102, 103];
println!("arr[0] = {}", arr[0]);
println!("arr[1] = {}", arr[1]);
println!("arr[2] = {}", arr[2]);
let arr1 = ['a', 'b'];
println!("arr1: {:?}", arr1)
let [x, y, z] = arr; // Destructuring the array.
println!("x = {}", x);
println!("y = {}", y);
println!("z = {}", z);
// Creates array of length 3 with value 10.
let arr = [10; 3];
println!("{:?}", arr); // [10, 10, 10]
- Its data type to store a string.
- A
String
is stored as a vector of bytes (Vec<u8>
), but guaranteed to always be a valid UTF-8 sequence.String
is heap allocated, growable and not null terminated.
// Immutable
let greet = String::from("Hello");
println!("{}", greet);
// Mutable
let mut greet = String::from("Hello");
greet.push_str(" World!");
println!("{}", greet);
- Data type that stores data as a key value pair. Data inside the struct can be of any type.
- Usually uses snake case to define function names.
- Function parameterd/argumentd must declare their type.
- Function return type is decared using the arrow '->' symbol.
fn print_number(a: u8, b: i8) {
println!("a = {}, b = {}", a, b);
}
fn sum_number(a: u32, b: u32) -> u32 {
return a + b;
}
- Statements are instructions that performs action and do not return a value.
- Expression also performs action but it restuns a value. Expressions do not include ending semicolons.
// Here 'let' is the statement.
// It creates a variable and assigns value 5 to it.
let x = 3;
let y = {
x + 1
};
println!("x = {}", x); // x = 3
println!("y = {}", y); // x = 4
let num = 10;
if num % 2 == 0 {
println!("Number is divisible by 2");
} else if num % 3 == 0 {
println!("Number is divisible by 3");
} else {
println!("Number is not divisible by 2 and 3", );
}
// Here if is used as an expression.
// Note: the type of the return value must be same each
let num_type = if num % 2 == 0 {
"even"
} else {
// if this were integer 5, an error will occur bcoz
// the return type of the value must be same.
"odd"
};
println!("Number is {}", num_type);
- Code inside a loop block will run infinitely.
- break statement will stop the loop.
- To return a value from loop add the value after the break expression.
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter;
}
};
println!("result = {}", result); // result = 10
let mut counter = 5;
while counter != 0 {
counter -= 1;
println!("counter = {}", counter);
}
let test_tup = [10, 20, 30];
for data in test_tup.iter() {
println!("{}", data);
}
- Stack and Heap are parts of memory that are available to rust to use at runtime.
- The Stack stores values in the order it gets them and removes the values in the opposite order. This is referred to as last in, first out(LIFO).
- All data stored on the stack must have a known, fixed size. Data with an unknown size at compile time or a size that might change must be stored on the heap instead.
- The Heap stores values in the order it gets them and removes the values in the same order. This is referred to as first in, first out(FIFO).
- The heap is less organized: when you put data on the heap, you request a certain amount of space. The operating system finds an empty spot in the heap that is big enough, marks it as being in use, and returns a pointer, which is the address of that location. This process is called allocating on the heap and is sometimes abbreviated as just allocating.
- Pushing values onto the stack is not considered allocating. Because the pointer is a known, fixed size, you can store the pointer on the stack, but when you want the actual data, you must follow the pointer.
- Pushing to the stack is faster than allocating on the heap because the oper-ating system never has to search for a place to store new data; that location is always at the top of the stack. Comparatively, allocating space on the heap requires more work, because the operating system must first find a big enough space to hold the data and then perform bookkeeping to prepare for the next allocation.
- When your code calls a function, the values passed into the function (including, potentially, pointers to data on the heap) and the function’s local variables get pushed onto the stack. When the function is over, those values get popped off the stack.
- Rust uses Ownership rules to manage memory on stack and heap instead of the a garbage collector.
Rust don't have an Garbage collector. It manages memory by concept called ownership.
- Watch the following video to get the idea of ownership.
- Scope is the range within a program for which an item is valid.
{ // s is not valid here; it's not yet declared
let s = "hello"; // s is valid from this point forward
println!("{}", s);
} // this scope is now over, and s is no longer valid
- Consider the following scenarios:
Scenario 1
ley x = 5;
let y = x;
Here values of x is fixed ie, u32 so the value of both x and y are pushed on the stack.
Scenario 1
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s2); // This will throw error bcoz scope s1
// is no longer available in the memory.
Here since the value of s1 is of not fixed, rust stores a pointer to
the memory that holds the contents of the string, a length, and a capacity data into the stack and the contents of the string are stored in the queue.
Also unlike other programming languages after the linelet s2 = s1;
the s1 will be moved into s2(ie, pointer data of s1 in stack copied to s2 and s1 is deleted from the stack.)