Thevetats Ramblings

Explore

About
Blogs
Misc
Resume
Services
Testing
Tools

Blogs

Env

Freshstart

Aliases
How I config my System76
Un-F%ck your M2 for development
ZSH Functions

Toolbelt

What's usually in the workvan

Rust

Notes

Primeagen's Rust for TS Devs

RustGoTs

Primeagen's Polyglot Class 1
Primeagen's Polyglot Class 2
Primeagen's Polyglot Class 3

Tauri

Setting up Tauri with Vite

WebDev

Ai

TheBeast

Slaying the beast

ComponentLibary

Salt Life
Submodules in Git

Sql

Useful SQL

Unocss

Just one more...
Setting up UnoCSS in a Vite Project

Vue

Reference

Suspense
Transitions

Primeagen's Rust for TS Devs

Published
April 21, 2023
Tags
#notes#typescript#rust

Table of Contents

  • Example 1:
  • Example Two:
    • V1:
    • V2:
    • V3:
  • Example Three: Enums
  • Example Four:
  • Example Five:
  • Example Six:
  • Example Seven
  • Borrow Checker
  • Traits

Wrote rust for almost a year and a half straight from 2019-2021. Didnt use it for a year plus and really lost the rythm. Doing a refresher class on frontend masters to get back up to speed.

Example 1:

  • Create a list initialized with 1,2,3
  • Add 1 to each item in the list
  • Print the list
typescript
const a = [1,2,3].map((val:number) => val=val+1 )
console.log(a)
rust
fn main() {
  let items: Vec<i32> = vec![1, 2, 3]
    .iter()
    .map(|item| item + 1)
    .collect();
  println!("{:?}", items)
}

Could also be written as

rust
fn main() {
    let items = vec![1,2,3];
    let mut iter = items
        .iter()
        .map(|num| num + 1);

    let mut collected_items = vec![];

    while let Some(x) = iter.next() {
        collected_items.push(x)
    }

    println!("{:?}", collected_items)
}

OR

rust
fn main() {
    let items = vec![1,2,3];
    let iter = items
        .iter()
        .map(|num| num + 1);

    let mut collected_items = vec![];

    for x in iter {
        collected_items.push(x)
    }

    println!("{:?}", collected_items)
}

Collect Examples:

rust
let foo: String = vec!["this", "is", "pretty", "cool"]
    .into_iter()
    .collect();
rust
let foo: HashSet<isize> = vec![1,2,3]
    .into_iter()
    .collect();
rust
let foo: Hashmap<&str, usize> = vec!["this", "is", "pretty", "cool"]
    .into_iter()
    .enumerate()
    .map(|(idx, item)| (item,idx))
    .collect();

Example Two:

V1:

typescript
import { readFileSync } from "fs";

readFileSync('lines.txt').
    toString().
    split('\n').
    forEach(line => console.log(line))
rust
fn main() {
    let file = std::fs::read_to_string("lines.txt").unwrap();

    file
        .lines()
        .for_each(|line| println!("{line}"));
}

V2:

typescript
import { readFileSync } from "fs";

readFileSync('lines.txt').
    toString().
    split('\n').
    filter((_, i) => i % 2 === 0).
    forEach(line => console.log(line))
rust
fn main() {
    let file = std::fs::read_to_string("lines.txt").unwrap();

    file
        .lines()
        .enumerate()
        .filter(|(idx, _)| idx % 2 == 0)
        .for_each(|(_, line)| println!("{line}"));
}

V3:

typescript
import { readFileSync } from "fs";

readFileSync('lines.txt').
    toString().
    split('\n').
    filter((_, i) => i % 2 === 0).
    filter((_, i) => i >= 2 && i < 4).
    forEach(line => console.log(line))
rust
fn main() {
    let file = std::fs::read_to_string("lines.txt").unwrap();

    file
        .lines()
        .enumerate()
        .filter(|(idx, _)| idx % 2 == 0)
        .skip(2)
        .take(2)
        .for_each(|(_, line)| println!("{line}"));
}

Example Three: Enums

typescript
enum Color {
    Red,
    Green,
    Blue
}

function printColor(color: Color) {
    switch(color) {
        case Color.Red: console.log('Red'); break;
        case Color.Green: console.log('Green'); break;
        case Color.Blue: console.log('Blue'); break;
    }
}

printColor(Color.Red)
rust
enum Color {
    Red,
    Green,
    Blue,
}

fn print_color(color: Color) {
    match color {
        Color::Red => println!("Red"),
        Color::Green => println!("Green"),
        Color::Blue => println!("Blue"),
    }
}
fn main() {
    print_color(Color::Red)
}
rust
enum Color {
    Red,
    Green,
    Blue,
    Yellow,
}

impl Color {
    fn is_green(&self) -> bool {
        if let Color::Green = self {
            return true
        }
        false
    }

    fn is_green_parts(&self) -> bool {
        match self {
            Color::Red => false,
            Color::Green => false,
            Color::Blue => true,
            Color::Yellow => true,
        }
    }
}

fn print_color(color: Color) {
    match color {
        Color::Red => println!("Red"),
        Color::Green => println!("Green"),
        Color::Blue => println!("Blue"),
        Color::Yellow => println!("Yellow")
    }
}
fn main() {
    let color = Color::Green;

    println!("{:?}", color.is_green())
}

Example Four:

typescript
export type Custom = {
    age: number
    name: string
}

export type Item = number | string | Custom

function append(list: Item[]) {
    list.push("hello Fem!")
}

const list: Item[] = [1, 2, 3]
append(list)
console.log(list)

// Grr Typescript Bad
const numbers: number[] = [1, 2, 3]
append(numbers)
console.log(numbers)
rust
#[derive(Debug)]
struct Custom {
    age: usize,
    name: String
}

#[derive(Debug)]
enum Item {
    Number(usize),
    String(String),
    MyCustom(Custom)
}

fn append(items: &mut Vec<Item>) {
    items.push(Item::String("hello, FEM".to_string()))
}

fn main() {
    let mut items: Vec<Item> = vec![];
    append(&mut items);
    println!("{:?}", items)
}

Example Five:

typescript
function multFive(value: number | undefined ): number {
    return (value ?? 0 ) * 5
}
rust
fn mult_five(num: Option<usize>) -> usize {
    num.unwrap_or(0) * 5
}

fn mult_five_option(num: Option<usize>) -> Option<usize> {
  num.map(|num| num * 5)
}

fn mult_five_other(num: Option<usize>) -> Option<usize> {
    Some(num? * 5)
}

Example Six:

Ways to handle errors:

rust
if let Ok(value) = a_function_that_can_error() {
  //something with the value
}

match a_function_that_can_error() {
    Ok(value) => println!("Yusss: {}", value);
    Err(e) => eprintln!("Oh no: {}", e);
}

// Dont care about error
_ = a_function_that_can_error();

// Yolo the error
let foo = a_function_that_can_error().unwrap();

// Respectful Yolo
let foo = a_function_that_can_error().expect("Should never fail");

// Use Default
let foo = a_function_that_can_error().unwrap_or(0);

// Convert to Option
let foo = a_function_that_can_error().ok();

// Map the good stuff
let foo = a_function_that_can_error()
    .map(|value| value + 1);

// And then?
let foo = a_function_that_can_error()
    .and_then(|value| another_possible_error(value))
    .and_then(|value| again(value));

// If the function returns an error you can do this!
let foo = a_function_that_can_error()?;

Example Seven

typescript
import fs from "fs"

const fileName = process.argv[2]

if (!fileName) {
    throw new Error("A file to watch must be specified!")
}

fs.readFileSync(fileName).
    toString().
    split("\n").
    forEach((line) => {
    console.log(line)
    })
rust
fn main() {
    let file_name = std::env::args().nth(1)
        .expect("The Filename must be passed in");

    let file = std::fs::read_to_string(file_name)
        .expect("Can not read the file");

    file.lines().for_each(|line| println!("{}", line));
}

Borrow Checker

  1. There can only be one value owner
  2. There can be unlimited immutable borrows(reference) with no mutable references
  3. There can be only one mutable reference and no immutable references.
  4. A reference cannot outlive its value
rust
#[derive(Debug)]
struct Item {
    count: usize
}

fn add_one(mut item: &mut Item) {
    item.count += 1;
}

fn print_all(items: &Vec<Item>) {
    for item in items {
        println!("item: {:?}", item);
    }
}

fn main() {
    let mut item = Item { count: 1 };
    println!("item: {:?}", item);

    add_one(&mut item);
    println!("item: {:?}", item);

    let mut items = vec![Item { count: 1 }];
    let first = items.first_mut();
    println!("item: {:?}", first);

    print_all(&items);

    let first = items.get_mut(0);
    println!("first: {:?}", first);
    let second = items.get_mut(1);
    println!("second: {:?}", second);
}

Traits

typescript
interface Area {
  area(): number
}

class Rectangle implements Area {
  constructor(
    public x: number,
    public y: number,
    public width: number,
    public height: number,
  ) {}

  area(): number {
    return this.width * this.height
  }
}

class Circle {
  constructor(
    public x: number,
    public y: number,
    public radius: number,
  ) {}

  area(): number {
    return this.radius * this.radius * Math.PI
  }
}

main.rs

rust
use crate::shapes::{Circle, Rect, Area};
mod shapes;

fn main() {
    let rect = Rect { x: 0.0, y: 0.0, width: 10.0, height: 20.0 };
    let circle = Circle { x: 0.0, y: 0.0, radius: 10.0 };

    let rect_area = rect.area();
    let circle_area = circle.area();

    println!("Rect Area: {}", rect_area);
    println!("Circle Area: {}", circle_area);
}

shapes.rs

rust
use std::f64::consts::PI;

pub struct Rect {
    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64,
}

pub struct Circle {
    pub x: f64,
    pub y: f64,
    pub radius: f64,
}

pub trait Area {
    fn area(&self) -> f64;
}

impl Area for Circle{
    fn area(&self) -> f64 {
        self.radius * self.radius * PI
    }
}

impl Area for Rect {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}
rust
fn main() {
    let rect = Rect::default();
    let circle = Circle::default();

    let rect_area = rect.area();
    let circle_area = circle.area();

    println!("Rect: {}", rect);
    println!("Rect Area: {}", rect_area);
    println!("Circle: {}", circle);
    println!("Circle Area: {}", circle_area);

    let rect = Rect::default();

    println!("{}", rect);

    let rect = Rect::default();
    let rect2 = Rect::default();
    let circle = Circle::default();
    let circle2 = Circle::default();

    rect.collide(&rect2);
    circle.collide(&circle2);
    rect.collide(&circle);
}
Made from scratch with ❤️ by Thevetat