
Everyone starts with a Hello, world!. This post uses that three-line program as an excuse to install Rust properly on Ubuntu, understand what cargo does, and leave with a project that compiles — in about ten minutes.
Why Rust, in two sentences
Rust delivers C performance without a garbage collector while eliminating, at compile time, the class of bugs that produces the most CVEs in systems software: use-after-free, buffer overflows, and thread races. The price is a compiler that argues with you during the first week.
It is not a niche language: the Linux kernel removed Rust's experimental label in version 7.0, in April 2026, and Ubuntu 26.04 LTS already ships sudo and core utilities rewritten in it. The full story is in The history of the Rust language.
Installing with rustup
Do not use apt install rustc. Rust releases every six weeks and the distro package gets old quickly — besides not providing rustup, which manages versions. The official approach:
sudo apt update
sudo apt install -y build-essential curl # o Rust usa o linker do GCC
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Accept the default installation (option 1). When it finishes, load the environment in the current session — in subsequent sessions it loads automatically through ~/.bashrc:
source "$HOME/.cargo/env"
rustc --version
cargo --version
You should see something like rustc 1.98.1. If the command is not found, it is because ~/.cargo/bin was not added to PATH — the source above fixes it.
The first program, by hand
Before cargo, it is worth seeing the bare compiler. Create ola.rs:
fn main() {
println!("Olá, mundo!");
}
rustc ola.rs
./ola
Two things to notice. rustc generated a native binary — no VM, no interpreter, no runtime to install on the target machine. And println! has an exclamation mark: in Rust, that means it is a macro, not an ordinary function. You will see that exclamation mark often.
Now the right way: cargo
In practice, nobody invokes rustc manually. cargo is the project, dependency, and build manager — equivalent to what npm, pip and make do together in other languages.
cargo new ola
cd ola
cargo run
It creates the structure, compiles, and runs. What appeared:
ola/
├── Cargo.toml # nome, versão, dependências
├── .gitignore # já vem pronto
└── src/
└── main.rs # o seu código
The commands you will use every day:
cargo run # compila e executa
cargo build # só compila (binário em target/debug/)
cargo build --release # compila otimizado — bem mais lento, bem mais rápido
cargo check # verifica se compila, SEM gerar binário (o mais rápido)
cargo test # roda os testes
cargo fmt # formata o código no padrão da comunidade
cargo clippy # o linter: pega o que compila mas é má ideia
cargo check is Rust's productivity secret: while you write, it responds in a fraction of the time taken by build, because it does not generate machine code.
If clippy and fmt are not installed:
rustup component add clippy rustfmt
One step beyond “hello”: reading input
A Hello, world! does not show anything that makes the language different. This does — replace the contents of src/main.rs:
use std::io::{self, Write};
fn main() {
print!("Qual o seu nome? ");
io::stdout().flush().unwrap();
let mut nome = String::new();
io::stdin()
.read_line(&mut nome)
.expect("falha ao ler a entrada");
let nome = nome.trim();
if nome.is_empty() {
println!("Você não digitou nada.");
} else {
println!("Olá, {nome}! Bem-vindo ao Rust.");
}
}
cargo run
Three details worth more than the program:
let mut— in Rust everything is immutable by default. If you want to change it, you must say so. This is the opposite of most languages, and it is intentional.&mut nome— you are borrowing the variable so the function can write to it, without transferring ownership. This concept is Rust's core; the compiler ensures there is only one mutable borrow at a time..expect(...)— reading input can fail, and Rust forces you to handle it. There is no hidden exception: either you handle the error or the program does not compile.
Using a dependency
crates.io is the language's package repository. Adding one takes a single command:
cargo add rand
This writes the dependency to Cargo.toml automatically. Now a random draw:
use rand::Rng;
fn main() {
let sorteado = rand::rng().random_range(1..=100);
println!("Número sorteado: {sorteado}");
}
cargo run
On the first run it downloads and compiles the dependency and all its dependencies; subsequent runs use the cache. The file Cargo.lock, created automatically, locks the exact versions — commit it to version control along with the project if it is a binary.
Building the production binary
cargo build --release
ls -lh target/release/ola
./target/release/ola
The binary in release is optimized and does not require Rust to be installed on the target machine — only system libraries. That is why so many modern command-line tools are distributed as a single file.
Managing Rust versions
rustup update # atualiza a toolchain
rustup toolchain install nightly # instala o canal de desenvolvimento
cargo +nightly build # compila com ele, sem trocar o padrão
rustup default stable # volta ao estável
rustup show # o que está instalado e ativo
To pin the version for a specific project, create a rust-toolchain.toml in the root directory — rustup will automatically respect it inside that directory.
When you get stuck
You will get stuck, and that is fine. Rust's compiler is exceptionally instructive: it usually tells you not only what is wrong, but what to write instead. Read the entire message before searching Google — the answer is almost always in it.
rustc --explain E0502 # explicação longa de qualquer código de erro
And if you still cannot figure it out, pasting the message into an AI assistant in the terminal resolves most beginner roadblocks without taking you away from the keyboard.
Where to go next
- The official book, free and available in Portuguese: The Rust Book. It is the best starting point available.
- Rust by Example — if you learn better by reading code than prose.
- Rustlings — small exercises that intentionally fail to compile, for you to fix.
- Here on the blog: The history of the Rust language, with the borrow checker explained, and the main programming languages, to put Rust on the map.
Ten minutes, a native binary, and a crab. A good start.
Gear based on the official Rust logo (CC BY 4.0). Ferris, the unofficial mascot, by Karen Rustad Tölva.