Here I want to present programming in Rust basics for Linux environment, by Linux I mean modern distro such as Ubuntu 24.04 and Kernel 6.8 at least.
So first we need to understand how Rust works and how to build programs in Rust. Rust has several versions and we will discuss them here in details.
Rust compiler and build tool is dependent on C/C++ compiler. so we need to install gcc or llvm first, so for that we need to do the following:
For Ubuntu/Debian: sudo apt update && sudo apt install build-essential
For Fedora: sudo dnf install gcc
For Arch Linux: sudo pacman -S base-devel
For installing rust compiler run the following code in your terminal, and just follow simple instructions.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Using Cargo
When you start reading about Rust, you will soon meet Cargo, the standard tool used in the Rust ecosystem to build and run Rust application. Here we want to give a brief overview of what Cargo is and how it fits into the wider ecosystem of Rust application development.
Installation
Please follow the instructions on https://rustup.rs/
This will give you the Cargo build tool, (cargo) and the Rust compiler (rustc). You will also get rustup, a command line utility that you use to install different compiler versions.
After installing Rust, you should configure your PATH variable to be able to call rustc and cargo from command line. The PATH environment variable should contain standard binaries for Rust compiler and buidl tool – add this in PATH variable ~/.cargo/bin
source "$HOME/.cargo/env" – for just local usage
Edit ~/.bashrc and add the following to it
export PATH="$HOME/.cargo/bin:$PATH" – for user’s global usage
Then run the following commands to see versions.
rustc --version
cargo --version
The Rust ecosystem
The Rust ecosystem consists of a number of tools, of which the main ones are:
rustc: the Rust compiler that turns .rsfiles into binaries and other intermediate formats.cargo: the Rust dependency manager and build tool. Cargo knows how to download dependencies, usually hosted on https://crates.io, and it will pass them torustcwhen building your project. Cargo also comes with a built-in test runner which is used to execute unit test.rustup: the Rust toolchain installer and updater. This tool is used to install and updaterustcandcargowhen new versions of Rust are released,rustupcan also download documentation for the standard library. You can have multiple versions of Rust installed at once andrustupwill let you switch between then as needed.
Rust has editions: the current edition is Rust 2024. Previous editions were Rust 2015, Rust 2018, and Rust 2021.
What is Rust?
Rust is new programming language that had its 1.0 release in 2015:
- Rust is statically compiled language in a similar role as C++
- rustc uses LLVM as its backend
- Rust supports many platforms and architectures – x86, ARM, WebAssembly, …
- Linux, Mac, Windows, …
- Rust is used for wide range of devices
- firmware and boot loaders
- smart displays
- mobile phones
- desktops
- servers
Rust is in the same area as C++.
- High flexibility
- High level of control
- Can be scaled down to very constrained devices such as microcontrollers
- Focuses on reliability and safety without sacrificing performance
Benefits of Rust
Some unique selling points of Rust:
- Compile time memory safety – whole classes of memory bugs are prevented at compile time
- No uninitialized variables
- No double-frees
- No NULL pointers
- No forgotten locked mutexes
- No data races between threads
- No iterator invalidation
- No undefined runtime behavior – what a Rust statement does is never left unspecified
- Array access is bounds checked
- Integer overflow is defined (panic or wrap-around)
- Modern language features – as expressive and ergonomic as higher-level languages
- Enums and pattern matching
- Generics
- No overhead FFI
- Zero-cost abstractions
- Great compiler errors
- Built-in dependency manager
- Built-in support for testing
- Excellent Language Server Protocol support
Types and Values
Hello World
hello_world.rs
fn main() {
println!("Hello World")
}
What you see:
Functions are introduced with fn
The main function is the entry point for the program
Blocks are delimited by curly braces like in C and C++
Statements end with semicolon ;println is a macro, indicated by the ! in the invocation
Rust strings are UTF-8 encoded and can contain any Unicode character
Rust is very much like other languages in the C/C++/Java tradition. It is imperative and it doesn’t try to reinvent things unless absolutely necessary. Rust is modern with full support for Unicode. Rust uses macros for situations where you want to have a variable number of arguments (no function overloading). println! is a macro because it needs to handle an arbitrary number of arguments based on the format string, which can’t be done with a regular function. Otherwise it can be treated like a regular function. Rust is multi-paradigm. For example, it has powerful object-oriented programming features, and, while it is not a functional language, it includes a range of functional concepts.
Variables
Rust provides type safety via static typing. Variables bindings are made with let:
fn main() {
let x: i32 = 10;
println!("x: {x}");
// x = 20;
// println!("x: {x}");
}
Uncomment the x = 20 to demonstrate that variables are immutable by default. Add the mut keyword to allow changes.
Warnings are enabled for this example, such as for unused variables or unnecessary mut. These are omitted in most examples to avoid distracting warnings. Try removing the mutation but leaving the mut keyword in place.
The i32 here is the type of the variable. This must be known at compile time, but type inference (covered later) allows the programmer to omit it in many cases.
Values
Here are some basic built-in types, and the syntax for literal values of each type.
| Types | Literals | |
| Signed integers | i8, i16, i32, i64, i128, isize | -10, 0, 1_000, 123_i64 |
| Unsigned integers | u8, u16, u32, u64, u128, usize | 0, 123, 10_u16 |
| Floating point numbers | f32, f64 | 3.14, -10.0e20, 2_f32 |
| Unicode scalar values | char | 'a', 'A', '-' |
| Boolean | bool | true, false |
The types have widths as follows.
iN, uNandfNareNbits wideisizeandusizeare the width of a pointercharis 32 bits wideboolis 8 bits wide
There are a few syntaxes that are not shown above:
All underscores in numbers can be left out, the are for legibility only. So 1_000 can be written as 1000 (or 10_00), and 123_i64 can be written as 123i64.
Arithmetic
arithmetic.rs
fn interproduct(a: i32, b: i32, c: i32) -> i32 {
return a * b + b * c + c * a;
}
fn main() {
println!("results: {}", interproduct(120, 100, 248));
}
This is the first time we have seen a function other than main, but the meaning should be clear: it takes three integers, and returns an integer. Functions will be covered in more detail later.
Arithmetic is very similar to other languages, with similar precedence.
What about integer overflow? In C and C++ overflow of signed integers are actually undefined, and might do unknown things at runtime. In Rust, it’s defined.
Change the i32‘s to i16 to see an integer overflow, which panics (checked) in a debug build and wraps in a release build. There are other panic options, such as overflowing, saturating, and carrying. These are accessed with method syntax, e.g. (a * b).saturating_add(b * c).saturating_add(c * a).
In fact, the compiler will detect oveflow of constant expressions, which is why the example requires a separate function.
Type Inference
Rust will look at how the variable is used to determine the type:
inference.rs
fn takes_u32(x: 32) {
println!("u32: {x}");
}
fn takes_i8(y: i8) {
println!("i8: {y}");
}
fn main() {
let x = 10;
let y = 20;
takes_u32(x);
takes_i8(y);
}
This example demonstrates how the Rust compiler infers types based on constraints given by variable declarations and usages.
It is very important to emphasize that variables declared like this are not of some soft of dynamic “any type” that can hold any data. The machine code generated by such declaration is identical to the explicit declaration of a type. The compiler does the job for us and helps us write more concise code.
When nothing constrains the type of an integer literal, Rust defaults to i32. This is sometimes appears as {integer} in error messages. Similarly, floating-point literals default to f64.

Leave a Reply