Logo

~/saidqb cat ecosystem/programming-language/rust.md

Rs

Rust

Systems language, memory-safe tanpa garbage collector

commit by saidqb

Intro

Rust: bahasa systems programming, cepat seperti C/C++ tapi memory-safe tanpa garbage collector — dijamin lewat ownership & borrowing yang dicek saat compile time, bukan runtime.

Get Started

bash
# install via rustup
rustup update
rustc --version && cargo --version

cargo new my_project      # bikin project baru + git init
cd my_project
cargo run                 # compile + jalankan

Syntax

rust
fn main() {
    let name = "SaidQB";
    println!("Halo, {name}!");
}
  • Setiap program butuh fungsi main() sebagai entry point.
  • Statement diakhiri ;; block dibungkus { }.
  • ! di belakang nama menandakan macro, misal println!.

Output

rust
println!("halo");                  // print + newline
print!("tanpa newline");
eprintln!("ke stderr");

let name = "SaidQB";
println!("Halo, {name}!");         // interpolasi langsung
println!("Halo, {}!", name);       // positional
println!("{:.2}", 19.999);         // format: 2 desimal -> 20.00
let s = format!("{name} - {}", 8); // format! -> hasilnya String

Comments

rust
// komentar satu baris
/* komentar
   banyak baris */
/// doc comment untuk item di bawahnya (dipakai `cargo doc`)
//! doc comment untuk module/file itu sendiri

Variables

rust
let name = "SaidQB";        // immutable by default
let mut age = 8;             // mutable, wajib pakai `mut` biar bisa diubah
age += 1;

let age = "delapan";         // shadowing: bikin binding baru, boleh beda tipe

Data Types

rust
let i: i32 = -8;             // signed integer (i8..i128, isize)
let u: u32 = 8;              // unsigned integer (u8..u128, usize)
let f: f64 = 19.99;          // float (f32, f64)
let b: bool = true;
let c: char = 'R';           // 1 karakter unicode, pakai kutip satu
let t: (i32, f64, char) = (8, 19.99, 'R');   // tuple
let a: [i32; 3] = [1, 2, 3]; // array

Constants

rust
const MAX_POINTS: u32 = 100_000;   // wajib deklarasi tipe, wajib UPPER_SNAKE_CASE
const PI: f64 = 3.14159;
// beda dari `let`: const selalu immutable dan nilainya harus diketahui saat compile time

Operators

rust
5 + 3; 5 - 3; 5 * 3; 5 / 3; 5 % 3;         // aritmatika
5 == 5; 5 != 3; 5 > 3; 5 <= 3;              // perbandingan
true && false; true || false; !true;        // logika
let mut x = 5; x += 1; x *= 2;               // compound assignment

Booleans

rust
let active: bool = true;
let is_adult = 8 >= 18;      // hasil comparison langsung bool

if active {
    println!("aktif");
}

If..Else

rust
let age = 18;
if age >= 18 {
    println!("dewasa");
} else if age >= 13 {
    println!("remaja");
} else {
    println!("anak-anak");
}

let status = if age >= 18 { "dewasa" } else { "belum" };   // if sebagai expression

Match

rust
let number = 3;
match number {
    1 => println!("satu"),
    2 | 3 => println!("dua atau tiga"),      // banyak pattern
    4..=6 => println!("empat sampai enam"),   // range
    _ => println!("lainnya"),                 // wajib ada, exhaustive check
}

let desc = match number {
    n if n < 0 => "negatif",    // match guard
    0 => "nol",
    _ => "positif",
};

Loops

rust
let mut i = 0;
let result = loop {
    i += 1;
    if i == 10 {
        break i * 2;      // loop bisa `break` dengan nilai balik
    }
};

While Loops

rust
let mut i = 0;
while i < 5 {
    println!("{i}");
    i += 1;
}

For Loops

rust
for i in 0..5 { println!("{i}"); }          // 0..5 eksklusif
for i in 0..=5 { println!("{i}"); }         // 0..=5 inklusif

let tags = ["rust", "go", "php"];
for tag in tags.iter() { println!("{tag}"); }
for (i, tag) in tags.iter().enumerate() { println!("{i}: {tag}"); }

Functions

rust
fn greet(name: &str) -> String {
    format!("Halo, {name}!")     // tanpa `;` -> jadi return value (expression)
}

fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        return Err("division by zero".to_string());   // early return pakai `return`
    }
    Ok(a / b)
}

Scope

rust
fn outer() {
    let x = 5;                 // x hidup selama scope outer()
    {
        let y = 10;             // y hanya hidup di dalam block ini
        println!("{x} {y}");
    }
    // y sudah keluar dari scope di sini, tidak bisa dipakai lagi
}

Strings

rust
let s1: &str = "halo";                 // string slice, immutable, biasanya literal
let mut s2: String = String::from("halo");  // owned, growable, heap-allocated
s2.push_str(" dunia");
s2.push('!');

s2.len(); s2.to_uppercase(); s2.trim();
s2.split(',').collect::<Vec<&str>>();
let combined = format!("{s1} {s2}");

Ownership

rust
let s1 = String::from("halo");
let s2 = s1;                    // s1 "pindah" (moved) ke s2, s1 tidak bisa dipakai lagi
// println!("{s1}");            // error: value borrowed after move

let s3 = s2.clone();            // clone kalau memang butuh duplikat data asli

fn take_ownership(s: String) { println!("{s}"); }  // s dipindah ke dalam fungsi
take_ownership(s3);              // s3 tidak bisa dipakai lagi setelah ini

Borrowing

rust
fn print_len(s: &String) -> usize { s.len() }   // borrow (&), tidak ambil ownership
let s = String::from("halo");
let len = print_len(&s);         // s masih bisa dipakai setelah ini

fn append(s: &mut String) { s.push_str("!"); }  // mutable borrow
let mut s = String::from("halo");
append(&mut s);
// aturan: boleh banyak &T (immutable borrow) sekaligus, tapi cuma satu &mut T dalam satu waktu

Data Structures

Rust punya beberapa collection bawaan, dipilih sesuai kebutuhan:

  • Array — ukuran fix, dicek saat compile time.
  • Vector — mirip array tapi bisa tumbuh (heap-allocated).
  • Tuple — kumpulan nilai beda tipe, ukuran fix.
  • HashMap — key-value pairs.
  • Struct — data custom dengan field bernama.
  • Enum — tipe dengan beberapa varian yang mungkin.

Arrays

rust
let arr: [i32; 3] = [1, 2, 3];       // ukuran fix, tidak bisa nambah/kurang
let zeros = [0; 5];                   // [0, 0, 0, 0, 0]
arr[0]; arr.len();

Vectors

rust
let mut v: Vec<i32> = vec![1, 2, 3];
v.push(4);
v.pop();
v[0]; v.len();
v.iter().sum::<i32>();
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();

Tuples

rust
let point: (i32, i32, &str) = (10, 20, "A");
point.0; point.1; point.2;             // akses via index
let (x, y, label) = point;              // destructuring

HashMap

rust
use std::collections::HashMap;

let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("SaidQB"), 90);
scores.entry(String::from("Guest")).or_insert(0);   // insert kalau belum ada

if let Some(score) = scores.get("SaidQB") {
    println!("{score}");
}

for (name, score) in &scores { println!("{name}: {score}"); }

Structs

rust
struct User {
    name: String,
    email: String,
    active: bool,
}

impl User {
    fn new(name: &str, email: &str) -> Self {
        User { name: name.to_string(), email: email.to_string(), active: true }
    }
    fn greet(&self) -> String { format!("Halo, {}", self.name) }
}

let user = User::new("SaidQB", "said@example.com");
println!("{}", user.greet());

Enums

rust
enum Status {
    Active,
    Inactive,
    Banned(String),          // variant dengan data
}

let status = Status::Banned("spam".to_string());
match status {
    Status::Active => println!("aktif"),
    Status::Inactive => println!("nonaktif"),
    Status::Banned(reason) => println!("banned: {reason}"),
}