node to rust - deptno/deptno.github.io GitHub Wiki

node-to-rust

24일 μ½”μŠ€λ‘œ node μˆ™λ ¨μžλ“€ μœ„ν•œ 러슀트 κ°€μ΄λ“œ

Day 1: From nvm to rustup

Day 2: From npm to cargo

npm cargo
init init ν˜„μž¬ 디렉토리 κΈ°μ€€
new 디렉토리 ν•¨κ»˜ 생성
run build + execute
install fetch
install [package_name] add
uninstall rm
install --global install ~/.cargo/bin
test test
publish publish
run [start] run --exmaple xxx @todo
benchmarks bench
build build
- build --release
clean clean
docs doc --open
- check tsc --noEmit
- clippy eslint

npm κ³Ό 달리 task runner λ₯Ό κ°€μ§€μ§€ μ•Šμ•˜λ‹€. λ•Œλ¬Έμ— 여전이 makefile 이 μ‚¬μš©λœλ‹€.
μ €μžλŠ” just λ₯Ό μΆ”μ²œ

cargo install just

workspaces & monorepo

Cargo.toml

[workspace]
members = [
  "crates/*"
]

[dependencies]
other-project = { path = "../other-project"}

좔가적인 툴

  • cargo-edit - λ””νŽœλ˜μ‹œ 버전 λ³€κ²½
  • cargo-workspaces(cargo ws) - lerna like
  • cargo-expand - macro
  • tomlq - jq like

Day 3: Setting up VS Code

core plugin

  • rust-analyzer
  • vadimcn.vscode-lldb
  • bungcip.better-toml
  • crates
  • search-crates-io

Day 4: Hello World (and your first two WTFs)

String vs &str

Day 5: Borrowing & Ownership

Day 6: Strings, part 1

&str -> String μ „ν™˜μ„ μœ„ν•΄ .to_owned() λ₯Ό μ‚¬μš©ν•œλ‹€.

  • .to_string() 은 Display trait 을 μ§€μ›ν•˜κΈ° μœ„ν•œ λ©”μ†Œλ“œ
  • .into() 은 νƒ€κ²Ÿνƒ€μž…μœΌλ‘œμ˜ μ „ν™˜μ„ μœ„ν•œ From,Into trait 의 κ΅¬ν˜„

Day 7: Syntax and Language, part 1

arrayλŠ” 컴파일 νƒ€μž„μ— 길이와 λͺ¨λ“  μ›μ†Œκ°€ μ΄ˆκΈ°ν™” λ˜μ–΄μ•Όν•œλ‹€. 일반적으둜 js λ§€μΉ­λ˜λŠ”κ±΄ VecDeque 으둜 μ–‘λ°©ν–₯ 접근이 κ°€λŠ₯ν•˜λ‹€.

  • Vec
  • VecDeque: μ–‘μͺ½μ—μ„œ push, pop 이 κ°€λŠ₯ν•˜λ‹€.

Day 8: Language Part 2: From objects and classes to HashMaps and structs

struct: μ•Œλ €μ§„ ν‚€ 셋을 κ°€μ§„ 데이터 μ…‹μ˜ 경우 map(hashmap): λͺ¨λ₯΄λŠ” ν‚€μ…‹ + 동일 νƒ€μž…

use std::collections::HashMap;

fn main() {
  let mut map = HashMap::new();
  map.insert("key1", "value1");
  map.insert("key2", "value2");

  println!("{}", map.get("key1").unwrap_or(&""));
  println!("{}", map.get("key2").unwrap_or(&""));
}

"" 의 νƒ€μž…μ€ &str map.get("key1") 의 νƒ€μž…μ€ Option<&&str> 이 λœλ‹€. &str 이고 get() 의 경우 μ†Œμœ κΆŒ 이전이 되면 map μ—μ„œ ν•΄λ‹Ή value κ°€ μ œκ±°λ˜μ–΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— borrowing(&) 이 λ˜μ•Όν•œλ‹€.

Day 9: Language Part 3: Class Methods for Rust Structs (+ enums!)

struct A {
  color: String
}
imple A {
  pub fn new() -> {
    Self {
      color: "red".to_owned(),
    }
  }
}
  • new() λŠ” ν‚€μ›Œλ“œκ°€ μ•„λ‹ˆλΌ μ»¨λ²€μ…˜μ΄λ‹€.
  • #[derive(Debug)] ꡬ문은 Trait 의 default κ΅¬ν˜„μ„ μ œκ³΅ν•œλ‹€.
  • ν•¨μˆ˜λŠ” 기본적으둜 private 이닀.
  • 첫번째 인자λ₯Ό self ν˜Ήμ€ &self 둜 μ„ μ–Έν•˜λ©΄ μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œκ°€ λœλ‹€.
    • self: Self
    • &self: &Self
  • self λ₯Ό 인자둜 μ„ μ–Έν•˜λŠ” 경우 μ˜€λ„ˆμ‰½μ„ κ°€μ§€κ²Œ λ˜λ―€λ‘œ 이후 μΈμŠ€ν„΄μŠ€λ₯Ό μžƒκ²Œ λœλ‹€.
    • μžλ°”μŠ€ν¬λ¦½μ˜ .map() 처럼 μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄μ„œ λ°˜ν™˜ν•˜λŠ” 경우
    • μ†Œλ©Έμžμ™€ 같은 역할을 ν•˜λŠ” 경우
    • λ©”μ†Œλ“œ 체이닝 enums 은 union type 을 μ²˜λ¦¬ν•  수 μžˆλ‹€.

Day 10: From Mixins to Traits

Trait 은 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ Mixins 이닀. λ©”μ†Œλ“œμ˜ 집합이라고 μƒκ°ν•˜λ„λ‘ ν•œλ‹€.

Day 11: The Module System

  • λͺ¨λ“  μ •μ˜λŠ” private이 default
  • trait methods, enum variants λŠ” default κ°€ public
  • visibility λŠ” λͺ¨λ“ˆμ˜ κ²ƒμ΄λ―€λ‘œ λͺ¨λ“ˆ λ‚΄μ—μ„œλŠ” λ¬΄κ΄€ν•˜κ²Œ μ°Έμ‘°κ°€ κ°€λŠ₯ν•˜λ‹€.
  • pub(create) λ₯Ό 톡해 crate λ‚΄λΆ€μ—μ„œ μ ‘κ·Ό ν—ˆμš©
  • pub(super) λΆ€λͺ¨μ—κ²Œλ§Œ ν—ˆμš©

Day 12: Strings, Part 2

ν•¨μˆ˜ μΈμžλŠ” &String, String 이 μ•„λ‹Œ &str λ‘œν•œλ‹€.

  • String 은 Borrow 이 κ΅¬ν˜„λ˜μ–΄μžˆμ–΄ μžλ™ μ»¨λ²„νŒ…μ΄ λœλ‹€.

  • Display κ΅¬ν˜„ν•¨μœΌλ‘œμ¨ .to_string() 을 얻을 수 μžˆλ‹€.

  • Borrow<str> - 더 λ§Žμ€ κ°€μ • + μ‹€νŒ¨ν•  수 μžˆλ‹€.

  • @todo AsRef<str> - 더 적은 κ°€μ • + μ‹€νŒ¨ν•  수 μ—†λ‹€.

Day 13: Results & Options

std::prelue 에 μ„ μ–Έλœ 것듀은 use μ„ μ–Έ 없이 μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

  • Some

  • None

  • unwrap() 은 Err(T), None 이 μ˜€λŠ” 경우 panic 을 λ°œμƒμ‹œν‚¨λ‹€.

  • unwrap_or(v) μ‹€νŒ¨ 없이 v λ₯Ό κΈ°λ³Έκ°’μœΌλ‘œ 리턴

  • unwrap_or_else(|| {}) μ‹€νŒ¨ 없이 ν•¨μˆ˜λ₯Ό ν†΅ν•œ 값을 리턴

  • unwrap_or_default() Default trait 을 κ΅¬ν˜„ν•œ κ²½μš°μ— μ‚¬μš©λ¨

맀직 value λŒ€μ‹  Option, Result λ₯Ό μ΄μš©ν•˜μž.

Day 14: Managing Errors

μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ 였λ₯˜λ₯Ό λ°˜ν™˜ ν•˜λŠ” ν•¨μˆ˜ μž‘μ„±ν•˜κΈ°

  1. Box
  • Box λŠ” 수λͺ… 만큼 μ‘΄μž¬ν•˜λŠ” μ–΄λ–€ κ°’μ˜ μ£Όμ†Œ
  • μ•„ν‚€ν…μ³μ˜ λΉ„νŠΈκ°€ 크기가 λœλ‹€.
  • Result λŠ” Err 에 μ œν•œμ΄ μ—†μœΌλ―€λ‘œ Error trait 을 κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ μ‹€νŒ¨ν•œλ‹€.
  1. custom Error type
  • impl std::error::Error for MyError {}
  • supertraits trait 이 μ˜μ‘΄ν•˜λŠ” trait
  • From, Into, TryFrom, TryInto κ΅¬ν˜„ ν•„μš”
  • From 은 νƒ€κ²Ÿ νƒ€μž…μ„ 보고 μžλ™μœΌλ‘œ Into λ₯Ό ν˜ΈμΆœν•œλ‹€.
  • Try* 은 μ‹€νŒ¨κ°€ κ°€λŠ₯ν•˜λ‹€. 리턴 νƒ€μž…μ€ Result κ°€ λœλ‹€.
  1. Use crate
  • thiserror - μ»€μŠ€ν…€ μ—λŸ¬, lib μ—μ„œ 주둜 μ‚¬μš©
#[derive(thiserror::Error, Debug)]
enum MyError {
  #[error("Environment variable not found")]
  EnvironmentVariableNotFound(#[from] std::env::VarError),
  #[error(transparent)]
  IOError(#[from] std::io::Error),
}
  • anyhow - 원본 μ—λŸ¬λ₯Ό κ·ΈλŒ€λ‘œ λ…ΈμΆœ, bin μ—μ„œ μ‚¬μš©

Day 15: Closures

  • Fn
  • FnMut
  • FnOnce - move 둜 μ†Œμœ κΆŒμ„ μžƒλŠ” 경우

@todo impl [trait] 은 ν•¨μˆ˜ 인자 ν˜Ήμ€ 리턴 κ°’ μ΄μ™Έμ—λŠ” μ‚¬μš©μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€. λ•Œλ¬Έμ— dyn [trait] 으둜 μ €μž₯이 ν•„μš”ν•˜λ‹€. dyn [trait] 은 unsized 이며 λŸ¬μŠ€νŠΈλŠ” 이λ₯Ό μ’‹μ•„ν•˜μ§€ μ•ŠλŠ”λ‹€.

Day 16: Lifetimes, references, and 'static

@todo T: 'static, &'static 은 λ‹€λ₯΄λ‹€ T: 'static 은 μ˜μ›νžˆ μ§€μ†λ˜λŠ” λ³€μˆ˜λ₯Ό μ˜λ―Έν•˜μ§€ μ•ŠλŠ”λ‹€.

Day 17: Arrays, Loops, and Iterators

  • 배열은 μ•Œλ €μ§„ 크기와 μ΄ˆκΈ°ν™”λ˜μ–΄ μžˆμ–΄μ•Όν•œλ‹€.
  • μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ Array λŠ” Vec κ³Ό λ§€μΉ­λœλ‹€.
  • VecDeque λŠ” μ–‘μͺ½μ—μ„œ μž…μΆœλ ₯이 κ°€λŠ₯ν•˜λ‹€.
    • Vec -> vec![]
  • for prop in hashmap.keys() { } -> .keys() λŠ” μž„μ˜ μˆœμ„œλ‘œ 쑰정이 λΆˆκ°€λŠ₯
  • for i in 0..max { }
  • while ((data = obj.dowork())) { }
  • while let Some(data) = obj.dowork() { }
  • loop { break; }
  • 'outer: loop { break 'outer; }
  • let value = loop { break "return value"; }

Iterator, Array, Vec -> ::iter()

  • Iterator λŠ” lazy ν•˜κ²Œ λ™μž‘ collect() λ“±μ˜ λ°˜ν™˜ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν• λ•Œ iterator λ“€μ˜ λ©”μ†Œλ“œ 듀이 μ‚¬μš©

  • Vec::iter() 둜 생성 or Vec::iter_mut() -> Iterator λ₯Ό 리턴

  • Iterator.collect() 둜 λ°˜ν™˜ -> νƒ€κ²Ÿμ— νƒ€μž…μ„ 지정해야함 eg, let a: Vec<_> = ...

  • Iterator.next() λ°˜λ³΅μžμ—μ„œ 단일 값을 μ–»μ„λ•Œ μ‚¬μš©

  • Iterator.filter() 2쀑 μ°Έμ‘°

  • Iterator.find() == Iterator.filter().next(), js 와 λ‹€λ₯΄κ²Œ find() λ₯Ό μ—¬λŸ¬λ²ˆ 호좜 κ°€λŠ₯

  • Iterator.forEach() iterator μ¦‰μ‹œ μ†ŒλΉ„, 일반 루프가 μ„ ν˜Έλœλ‹€.

  • Vec|Array.join(",") js 와 동일

  • Vec.push() Vec만 κ°€λŠ₯

  • Vec.pop() Vec만 κ°€λŠ₯

  • VecDeque.push_front() VecDeque만 κ°€λŠ₯

  • VecDeque.pop_front() VecDeque만 κ°€λŠ₯

.collect() λ₯Ό 톡해 νŠΉμ • 데이터 νƒ€μž…μ„ λ°˜ν™˜ν•˜μ§€ 말고, Iterator 자체λ₯Ό λ°˜ν™˜ν•΄μ„œ 지연평가와 μœ μ—°μ„±μ„ ν™•λ³΄ν•˜λ„λ‘ ν•œλ‹€.

Day 18: Async

λŸ¬μŠ€νŠΈλŠ” 러슀트의 Promise 인 Futures λ₯Ό κ°€μ§€κ³  μžˆλ‹€. κ·ΈλŸ¬λ‚˜ executor, reactor(node 의 event loop) κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.
이에 λŒ€ν•œ 폴리필은 μ•„λž˜μ™€ κ°™λ‹€.

  • tokio
  • smol
  • async-std
fn sync_fx() -> String {
}
async fn async_fx() -> String { // impl Future<Output = String>
}
#[tokio::main]
async fn main() {
  let msg = async_fx().await;
}

node 와 달리 .await 을 ν•˜κΈ°μ „μ—λŠ” μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.

비동기 ν΄λ‘œμ €

let closure = || async {
    println!("hello");
};

μ“°λ ˆλ“œλ‘œ μ „μ†‘λ˜μ–΄ μ‚¬μš©λ˜λŠ” 경우 μΈμžμ— 경계λ₯Ό μ£Όμ–΄μ•Όν•œλ‹€.

  • 'static - μ–Έμ œμ‚¬μš©λ μ§€ λͺ¨λ₯΄κΈ° λ•Œλ¬Έ
  • Send or Sync - Threadsafe

Day 19: Starting a large project

cargobook 은 Cargo.lock 을 λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œλŠ” μƒλž΅ν•˜λΌκ³  쑰언함(λ²„μ „κ΄€λ¦¬μ—μ„œλ‘œ 이해) ./Cargo.toml

[workspace]
members = ["crates/*"]

./crates/my-lib/Cargo.toml ./crates/cli/Cargo.toml

...
[dependencies]
my-lib = { path = "../my-lib" }
cargo run crates/cli
cargo run -p cli

test

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}

λ‚΄λΆ€ ν…ŒμŠ€νŠΈλŠ” 이와 같은 λ°©μ‹μœΌλ‘œλ§Œ ν•œλ‹€. tests 디렉토리λ₯Ό λ§Œλ“€μ–΄μ„œ μ™ΈλΆ€μ—μ„œ ν…ŒμŠ€νŠΈν•˜λŠ” 경우 pub μ ‘κ·Όμ§€μ‹œμžλ‘œ μ„€μ •λœ κ²½μš°μ—λ§Œ μ ‘κ·Όκ°€λŠ₯ν•˜λ‹€.

#cfg(flag) flag 그둜 on/off [#test] unit test -> cargo test 둜 μ‹€ν–‰λœλ‹€. assert ν•¨μˆ˜

  • assert!
  • assert_eq!
  • assert_ne!

crate 이름은 ν•˜μ΄ν”ˆ(-)을 μ‚¬μš©ν•˜μ§€λ§Œ μ½”λ“œμ—μ„œ μ°Έμ‘°μ‹œμ—λŠ” 언더바(_) 둜 μ°Έμ‘°ν•΄μ•Όλœλ‹€.

Day 20: CLI Arguments & Logging

  • structopt
  • log
  • env_logger
RUST_LOG=debug cargo run -p cli
RUST_LOG=package_name=debug cargo run -p cli
use structopt::{clap::AppSettings, StructOpt};

#[derive(StructOpt)]
#[structopt(
    name = "name",
    about = "about",
    global_settings(&[
      AppSettings::ColoredHelp
    ]),
)]
struct CliOptions {
    #[structopt(parse(from_os_str))]
    pub(crate) file_path: PathBuf,
}

fn main() {
    let options = CliOptions::from_args();
}
cargo run -p cli -- --help

cli 에 인자λ₯Ό λ„£μ–΄μ„œ μ‹€ν–‰ν•˜λ €λ©΄ -- 후에 인자λ₯Ό μž…λ ₯ν•œλ‹€.

#[derivte(StructOpt)]

Day 21: Building and Running WebAssembly

μ—λŸ¬ ν˜•μ‹μ„ λ³€ν™˜ν•˜λŠ” 방법

  1. From, Into, TryFrom, TryInto
  2. .map_err
fn fx() -> Result(Self, CustomError) {}
  #...
  .map_err(|e| CustomError::Something(e))?
}

μ›Ήμ–΄μ…ˆλΈ”λ¦¬(WebAssembly, μ΄ν•˜ wa)λ₯Ό μ§€μ›ν•˜λ―€λ‘œ ν•΄λ‹Ή 포맷으둜 포맷된 νŒŒμΌμ„ μ½μ–΄μ„œ κΈ°λŠ₯을 μˆ˜ν–‰ ν•  수 μžˆλ‹€. wa λŠ” 아직 μ™„λ²½ν•˜μ§€ μ•Šλ‹€. 아직 ν‘œμ€€ μŠ€νŽ™μ΄ μ—†μœΌλ―€λ‘œ rpc 와 같은 μ»¨μ…‰μœΌλ‘œ 처리λ₯Ό μ§„ν–‰ν•œλ‹€.

Day 22: Using JSON

  • serde
  • serde_json - json
  • rmp_serde massage - pack

Day 23: Cheating The Borrow Checker

λ©€ν‹° μŠ€λ ˆλ“œ μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€λ©΄ μ“°λ ˆλ“œκ°„ 데이터 이동을 μœ„ν•΄ μ•„λž˜ 두가지 Trait이 μ‘΄μž¬ν•œλ‹€.

  • Send - λΆˆλ³€ μ°Έμ‘°

  • Sync - κ°€λ³€ μ°Έμ‘°

  • Rc - Reference Count μ—¬λŸ¬ μ°Έμ‘°κ°€ μ‘΄μž¬ν•˜κ³  κ·Έ μ°Έμ‘°κ°€ λͺ¨λ‘ μ œκ±°λμ„λ•Œ λ©”λͺ¨λ¦¬λ₯Ό ν•΄μ œν•œλ‹€.

  • Arc - Atomic Reference Count, Rc 의 Send 버전이닀.

  • Mutex - ν•œ μ‹œμ μ— ν•˜λ‚˜μ˜ 읽고 μ“°κΈ°λ§Œ κ°€λŠ₯.

  • RwLock - Mutex 보닀 무겁닀. μ—¬λŸ¬ 읽기가 κ°€λŠ₯ν•˜λ©° ν•œ μ‹œμ μ— ν•˜λ‚˜μ˜ μ“°κΈ°λ§Œ κ°€λŠ₯ν•˜λ‹€.

  • parking_lot - Mutex, RwLock 보닀 λΉ λ₯΄λ©° Result λ₯Ό λ¦¬ν„΄ν•˜μ§€ μ•ŠλŠ”λ‹€.

Mutex, RwLock 등을 μ‚¬μš©ν• λ•Œ 락을 얻은 블둝이 사라지면 락이 μžλ™μœΌλ‘œ ν•΄μ œλœλ‹€. 쑰심해야할점을 락을 얻은 후에 .await λ“±μ˜ 비동기 λ™μž‘μ„ ν•˜κ²Œ 되면 λΆˆν•„μš”ν•œ 락을 작고 μžˆκ²Œλœλ‹€.

Tokio λŠ” 자체 Sync crate λ₯Ό κ°€μ§€κ³  μžˆλ‹€.

Day 24: Crates & Tools

link

⚠️ **GitHub.com Fallback** ⚠️