Primeagen's Rust for TS Devs
- Published
- Tags
- #notes#typescript#rust
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
- There can only be one value owner
- There can be unlimited immutable borrows(reference) with no mutable references
- There can be only one mutable reference and no immutable references.
- 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);
}