{"id":119,"date":"2017-04-05T18:55:03","date_gmt":"2017-04-05T21:55:03","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/2017\/04\/hello-world\/"},"modified":"2026-09-08T11:21:59","modified_gmt":"2026-09-08T14:21:59","slug":"hello-world","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/en\/2017\/04\/hello-world\/","title":{"rendered":"Hello World in Rust: installing and running on Ubuntu"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"Mascote do LinuxPro compilando o primeiro programa em Rust, Ferris na mesa e engrenagem 3D do Rust na parede\" src=\"\/wp-content\/uploads\/2026\/09\/hello-world-rust-v3.webp\" width=\"1486\" height=\"856\" \/><\/p>\n<p>Everyone starts with a <code data-no-translation=\"\">Hello, world!<\/code>. This post uses that three-line program as an excuse to install <strong>Rust<\/strong> properly on Ubuntu, understand what <code data-no-translation=\"\">cargo<\/code> does, and leave with a project that compiles \u2014 in about ten minutes.<\/p>\n<h2>Why Rust, in two sentences<\/h2>\n<p>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.<\/p>\n<p>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 <code data-no-translation=\"\">sudo<\/code> and core utilities rewritten in it. The full story is in <a href=\"\/en\/2026\/09\/a-historia-da-linguagem-rust\/\">The history of the Rust language<\/a>.<\/p>\n<h2>Installing with rustup<\/h2>\n<p>Do not use <code data-no-translation=\"\">apt install rustc<\/code>. Rust releases every six weeks and the distro package gets old quickly \u2014 besides not providing <code data-no-translation=\"\">rustup<\/code>, which manages versions. The official approach:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">sudo apt update\nsudo apt install -y build-essential curl    # o Rust usa o linker do GCC\n\ncurl --proto '=https' --tlsv1.2 -sSf https:\/\/sh.rustup.rs | sh<\/code><\/pre>\n<p>Accept the default installation (option 1). When it finishes, load the environment in the current session \u2014 in subsequent sessions it loads automatically through <code data-no-translation=\"\">~\/.bashrc<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">source \"$HOME\/.cargo\/env\"\n\nrustc --version\ncargo --version<\/code><\/pre>\n<p>You should see something like <code data-no-translation=\"\">rustc 1.98.1<\/code>. If the command is not found, it is because <code data-no-translation=\"\">~\/.cargo\/bin<\/code> was not added to <code data-no-translation=\"\">PATH<\/code> \u2014 the <code data-no-translation=\"\">source<\/code> above fixes it.<\/p>\n<h2>The first program, by hand<\/h2>\n<p>Before <code data-no-translation=\"\">cargo<\/code>, it is worth seeing the bare compiler. Create <code data-no-translation=\"\">ola.rs<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-rust\" data-no-translation=\"\">fn main() {\n    println!(\"Ol\u00e1, mundo!\");\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">rustc ola.rs\n.\/ola<\/code><\/pre>\n<p>Two things to notice. <code data-no-translation=\"\">rustc<\/code> generated a <strong>native binary<\/strong> \u2014 no VM, no interpreter, no runtime to install on the target machine. And <code data-no-translation=\"\">println!<\/code> has an exclamation mark: in Rust, that means it is a <em>macro<\/em>, not an ordinary function. You will see that exclamation mark often.<\/p>\n<h2>Now the right way: cargo<\/h2>\n<p>In practice, nobody invokes <code data-no-translation=\"\">rustc<\/code> manually. <strong>cargo<\/strong> is the project, dependency, and build manager \u2014 equivalent to what <code data-no-translation=\"\">npm<\/code>, <code data-no-translation=\"\">pip<\/code> and <code data-no-translation=\"\">make<\/code> do together in other languages.<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo new ola\ncd ola\ncargo run<\/code><\/pre>\n<p>It creates the structure, compiles, and runs. What appeared:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-text\" data-no-translation=\"\">ola\/\n\u251c\u2500\u2500 Cargo.toml      # nome, vers\u00e3o, depend\u00eancias\n\u251c\u2500\u2500 .gitignore      # j\u00e1 vem pronto\n\u2514\u2500\u2500 src\/\n    \u2514\u2500\u2500 main.rs     # o seu c\u00f3digo<\/code><\/pre>\n<p>The commands you will use every day:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo run                 # compila e executa\ncargo build               # s\u00f3 compila (bin\u00e1rio em target\/debug\/)\ncargo build --release     # compila otimizado \u2014 bem mais lento, bem mais r\u00e1pido\ncargo check               # verifica se compila, SEM gerar bin\u00e1rio (o mais r\u00e1pido)\ncargo test                # roda os testes\ncargo fmt                 # formata o c\u00f3digo no padr\u00e3o da comunidade\ncargo clippy              # o linter: pega o que compila mas \u00e9 m\u00e1 ideia<\/code><\/pre>\n<p class=\"translation-block\"><code>cargo check<\/code> is Rust's productivity secret: while you write, it responds in a fraction of the time taken by <code>build<\/code>, because it does not generate machine code.<\/p>\n<p class=\"translation-block\">If <code>clippy<\/code> and <code>fmt<\/code> are not installed:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">rustup component add clippy rustfmt<\/code><\/pre>\n<h2>One step beyond \u201chello\u201d: reading input<\/h2>\n<p>A <code data-no-translation=\"\">Hello, world!<\/code> does not show anything that makes the language different. This does \u2014 replace the contents of <code data-no-translation=\"\">src\/main.rs<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-rust\" data-no-translation=\"\">use std::io::{self, Write};\n\nfn main() {\n    print!(\"Qual o seu nome? \");\n    io::stdout().flush().unwrap();\n\n    let mut nome = String::new();\n    io::stdin()\n        .read_line(&amp;mut nome)\n        .expect(\"falha ao ler a entrada\");\n\n    let nome = nome.trim();\n\n    if nome.is_empty() {\n        println!(\"Voc\u00ea n\u00e3o digitou nada.\");\n    } else {\n        println!(\"Ol\u00e1, {nome}! Bem-vindo ao Rust.\");\n    }\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo run<\/code><\/pre>\n<p>Three details worth more than the program:<\/p>\n<ul>\n<li><strong><code data-no-translation=\"\">let mut<\/code><\/strong> \u2014 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.<\/li>\n<li><strong><code data-no-translation=\"\">&amp;mut nome<\/code><\/strong> \u2014 you are <em>borrowing<\/em> 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.<\/li>\n<li><strong><code data-no-translation=\"\">.expect(...)<\/code><\/strong> \u2014 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.<\/li>\n<\/ul>\n<h2>Using a dependency<\/h2>\n<p class=\"translation-block\"><a href=\"https:\/\/crates.io\/\" target=\"_blank\" rel=\"noopener\">crates.io<\/a> is the language's package repository. Adding one takes a single command:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo add rand<\/code><\/pre>\n<p>This writes the dependency to <code data-no-translation=\"\">Cargo.toml<\/code> automatically. Now a random draw:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-rust\" data-no-translation=\"\">use rand::Rng;\n\nfn main() {\n    let sorteado = rand::rng().random_range(1..=100);\n    println!(\"N\u00famero sorteado: {sorteado}\");\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo run<\/code><\/pre>\n<p>On the first run it downloads and compiles the dependency and all its dependencies; subsequent runs use the cache. The file <code data-no-translation=\"\">Cargo.lock<\/code>, created automatically, locks the exact versions \u2014 <strong>commit it to version control<\/strong> along with the project if it is a binary.<\/p>\n<h2>Building the production binary<\/h2>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">cargo build --release\nls -lh target\/release\/ola\n.\/target\/release\/ola<\/code><\/pre>\n<p>The binary in <code data-no-translation=\"\">release<\/code> is optimized and does not require Rust to be installed on the target machine \u2014 only system libraries. That is why so many modern command-line tools are distributed as a single file.<\/p>\n<h2>Managing Rust versions<\/h2>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">rustup update                    # atualiza a toolchain\nrustup toolchain install nightly # instala o canal de desenvolvimento\ncargo +nightly build             # compila com ele, sem trocar o padr\u00e3o\nrustup default stable            # volta ao est\u00e1vel\nrustup show                      # o que est\u00e1 instalado e ativo<\/code><\/pre>\n<p>To pin the version for a specific project, create a <code data-no-translation=\"\">rust-toolchain.toml<\/code> in the root directory \u2014 <code data-no-translation=\"\">rustup<\/code> will automatically respect it inside that directory.<\/p>\n<h2>When you get stuck<\/h2>\n<p>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 \u2014 the answer is almost always in it.<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">rustc --explain E0502     # explica\u00e7\u00e3o longa de qualquer c\u00f3digo de erro<\/code><\/pre>\n<p class=\"translation-block\">And if you still cannot figure it out, pasting the message into an <a href=\"\/en\/2026\/09\/assistentes-de-ia-no-terminal-linux\/\">AI assistant in the terminal<\/a> resolves most beginner roadblocks without taking you away from the keyboard.<\/p>\n<h2>Where to go next<\/h2>\n<ul>\n<li><strong>The official book<\/strong>, free and available in Portuguese: <a href=\"https:\/\/rust-br.github.io\/rust-book-pt-br\/\" target=\"_blank\" rel=\"noopener\">The Rust Book<\/a>. It is the best starting point available.<\/li>\n<li><strong><a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/\" target=\"_blank\" rel=\"noopener\">Rust by Example<\/a><\/strong> \u2014 if you learn better by reading code than prose.<\/li>\n<li><strong><a href=\"https:\/\/github.com\/rust-lang\/rustlings\" target=\"_blank\" rel=\"noopener\">Rustlings<\/a><\/strong> \u2014 small exercises that intentionally fail to compile, for you to fix.<\/li>\n<li>Here on the blog: <a href=\"\/en\/2026\/09\/a-historia-da-linguagem-rust\/\">The history of the Rust language<\/a>, with the <em>borrow checker<\/em> explained, and <a href=\"\/en\/2017\/05\/linguagens-de-programacao\/\">the main programming languages<\/a>, to put Rust on the map.<\/li>\n<\/ul>\n<p>Ten minutes, a native binary, and a crab. A good start.<\/p>\n<p style=\"font-size:.9em;opacity:.75\">Gear based on the <a href=\"https:\/\/www.rust-lang.org\/policies\/media-guide\">official Rust logo<\/a> (CC BY 4.0). Ferris, the unofficial mascot, by Karen Rustad T\u00f6lva.<\/p>","protected":false},"excerpt":{"rendered":"<p>Everyone starts with 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 \u2014 in about ten minutes. Why Rust, in two sentences Rust delivers C performance \u2026 <a title=\"Hello World in Rust: installing and running on Ubuntu\" class=\"read-more\" href=\"https:\/\/www.linuxpro.com.br\/en\/2017\/04\/hello-world\/\" aria-label=\"Read more about Hello World em Rust: instalando e rodando no Ubuntu\">Read more<\/a><\/p>","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[45,2],"tags":[302,14,397,158,396,5],"class_list":["post-119","post","type-post","status-publish","format-standard","hentry","category-desenv","category-linux","tag-cargo","tag-howto","tag-programacao","tag-rust","tag-rustup","tag-ubuntu"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/comments?post=119"}],"version-history":[{"count":5,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/119\/revisions"}],"predecessor-version":[{"id":1411,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/119\/revisions\/1411"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/media?parent=119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/categories?post=119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/tags?post=119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}