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 도구부터 만들어보면서 익숙해질 계획이다.