Hello World in Rust: installing and running on Ubuntu

Mascote do LinuxPro compilando o primeiro programa em Rust, Ferris na mesa e engrenagem 3D do Rust na parede

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

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.