Coming from JavaScript to Rust? Here’s a practical guide to help you make the transition.
Why Rust?
Rust offers:
- Memory safety without garbage collection
- Performance comparable to C/C++
- Modern tooling and package management
- WebAssembly support for web development
- Growing ecosystem with active community
Key Differences
1. Ownership System
Rust’s ownership system is unique:
// Rust: Ownership
let s1 = String::from("hello");
let s2 = s1; // s1 is moved to s2
// println!("{}", s1); // Error: s1 is no longer valid
// JavaScript: Reference
let s1 = "hello";
let s2 = s1; // s1 is still valid
console.log(s1); // Works fine
2. Mutability
Rust requires explicit mutability:
// Rust
let x = 5; // Immutable
let mut y = 10; // Mutable
y = 20; // OK
// JavaScript
let x = 5; // Mutable by default
x = 10; // OK
const y = 10; // Immutable
3. Type System
Rust has a strong, static type system:
// Rust: Explicit types
let x: i32 = 42;
let name: String = String::from("John");
// JavaScript: Dynamic types
let x = 42;
let name = "John";
Common Patterns
Variables and Mutability
// Immutable variable
let x = 5;
// Mutable variable
let mut y = 10;
y = 20;
// Constants
const MAX_POINTS: u32 = 100_000;
Functions
// Rust function
fn add(x: i32, y: i32) -> i32 {
x + y // No semicolon = return value
}
// With explicit return
fn subtract(x: i32, y: i32) -> i32 {
return x - y;
}
// JavaScript equivalent
function add(x, y) {
return x + y;
}
Structs (Objects)
// Rust struct
struct User {
name: String,
age: u32,
email: String,
}
impl User {
fn new(name: String, age: u32, email: String) -> Self {
User { name, age, email }
}
fn greet(&self) {
println!("Hello, I'm {}", self.name);
}
}
// Usage
let user = User::new(
String::from("John"),
30,
String::from("[email protected]"),
);
user.greet();
Enums and Pattern Matching
// Rust enum
enum Status {
Pending,
Approved,
Rejected,
}
// Pattern matching
fn handle_status(status: Status) {
match status {
Status::Pending => println!("Processing..."),
Status::Approved => println!("Approved!"),
Status::Rejected => println!("Rejected."),
}
}
// Enum with data
enum Result<T, E> {
Ok(T),
Err(E),
}
Error Handling
// Rust: Result type
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
// Usage
match divide(10.0, 2.0) {
Ok(result) => println!("Result: {}", result),
Err(error) => println!("Error: {}", error),
}
// With ? operator
fn calculate() -> Result<f64, String> {
let result = divide(10.0, 2.0)?;
Ok(result * 2.0)
}
Collections
// Vector (array)
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
vec.push(3);
// Or with macro
let vec = vec![1, 2, 3];
// HashMap
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key1", "value1");
map.insert("key2", "value2");
Iterators
// Rust iterators
let numbers = vec![1, 2, 3, 4, 5];
let doubled: Vec<i32> = numbers
.iter()
.map(|x| x * 2)
.filter(|x| x > &5)
.collect();
// JavaScript equivalent
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers
.map(x => x * 2)
.filter(x => x > 5);
Web Development with Rust
WebAssembly
Compile Rust to WebAssembly:
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[wasm_bindgen]
pub struct Calculator {
value: i32,
}
#[wasm_bindgen]
impl Calculator {
#[wasm_bindgen(constructor)]
pub fn new() -> Calculator {
Calculator { value: 0 }
}
#[wasm_bindgen]
pub fn add(&mut self, n: i32) {
self.value += n;
}
#[wasm_bindgen]
pub fn get_value(&self) -> i32 {
self.value
}
}
Web Frameworks
Popular Rust web frameworks:
- Actix Web: High-performance, actor-based
- Rocket: Easy to use, type-safe
- Axum: Modern, async-first
- Warp: Lightweight, functional
Learning Path
1. Start with Basics
- Variables and types
- Functions and control flow
- Ownership and borrowing
- Structs and enums
2. Practice with Projects
- Command-line tools
- Web servers
- WebAssembly modules
- System utilities
3. Learn Advanced Concepts
- Lifetimes
- Traits and generics
- Async/await
- Macros
Common Pitfalls
1. Fighting the Borrow Checker
// Common error
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // OK: multiple immutable references
let r3 = &mut s; // Error: can't have mutable and immutable references
2. Moving Values
// Error: value moved
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s1); // Error: s1 was moved
// Solution: Clone
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{}", s1); // OK
3. Lifetime Annotations
// Lifetime annotation needed
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
Resources
Official
Tools
cargo- Package managerrustfmt- Code formatterclippy- Linterrust-analyzer- Language server
Conclusion
Rust offers:
- Safety: Memory safety without GC
- Performance: Near C/C++ speed
- Modern: Great tooling and ecosystem
- Versatile: Systems programming to web
The learning curve is steep, but the benefits are worth it:
- Fewer bugs
- Better performance
- Modern tooling
- Growing ecosystem
Start small, practice regularly, and don’t fight the borrow checker—work with it!
Happy Rusting! 🦀