Rust의 소유권 시스템을 Node.js 개발자 관점에서 이해하기

왜 Rust를 보게 됐나

팀에서 고성능이 필요한 이미지 처리 API를 개발하는데, Node.js로는 한계가 있었다. C++로 네이티브 애드온을 만들까 고민하다가 Rust + neon을 검토하게 됐다.

소유권의 기본 규칙

Rust는 GC 없이 메모리 안전성을 보장하기 위해 컴파일 타임에 소유권을 체크한다.

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1의 소유권이 s2로 이동
    
    // println!("{}", s1); // 컴파일 에러!
    println!("{}", s2); // OK
}

JavaScript였다면 둘 다 접근 가능했겠지만, Rust는 한 시점에 하나의 소유자만 허용한다.

참조와 빌림(Borrowing)

소유권을 이전하지 않고 값을 사용하려면 참조를 쓴다.

fn calculate_length(s: &String) -> usize {
    s.len()
}

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("{}: {}", s1, len); // s1 여전히 사용 가능
}

불변 참조는 여러 개 가능하지만, 가변 참조는 한 번에 하나만 허용된다. 이게 데이터 레이스를 컴파일 타임에 방지하는 핵심이다.

Node.js 개발자가 느낀 차이

  • JavaScript: 런타임에 메모리 관리, 자유롭지만 예측 어려움
  • Rust: 컴파일 타임에 강제, 불편하지만 안전 보장

처음엔 컴파일러와 싸우는 느낌이었다. 하지만 일단 컴파일되면 메모리 관련 버그가 거의 없다는 점이 매력적이다.

다음 단계

라이프타임(Lifetime) 개념이 아직 어렵다. 실제 프로젝트에 적용하려면 더 학습이 필요할 것 같다. 일단 간단한 CLI 도구부터 만들어보면서 익숙해질 계획이다.