Rust 학습 가이드
카테고리별로 정리된 Rust 프로그래밍 가이드
기초 문법
소유권과 빌림 — Rust가 GC 없이 메모리를 관리하는 방법
컴파일 타임에 메모리 안전성을 보장하는 Rust의 핵심 규칙
Rust의 소유권 시스템은 GC 없이 메모리 안전성을 보장한다. 값 하나에 소유자 하나, 빌려줄 때는 읽기 전용 여러 개 또는 쓰기 전용 하나만 허용.
라이프타임 — Rust 컴파일러가 참조의 유효 범위를 추적하는 방법
'a가 뭔지 한 번에 이해하기
라이프타임은 참조가 유효한 범위를 컴파일러에게 알려주는 주석이다. 대부분의 경우 생략(elision) 가능하지만, 여러 참조가 얽힐 때 명시적으로 써야 한다.
패턴 매칭 — match와 if let으로 분기하기
switch/case의 상위 호환, Rust 코드의 핵심 표현 방식
Rust의 match는 값을 분해하면서 동시에 분기한다. 모든 경우를 빠짐없이 처리해야 하는(exhaustive) 컴파일러 강제 덕분에 누락 없는 분기가 보장된다.
Result와 ? 연산자 — Rust의 에러 처리 패턴
try-catch 없이 에러를 타입으로 다루는 방법
Rust에는 예외(exception)가 없다. 대신 Result<T, E> 타입으로 성공/실패를 명시하고, ? 연산자로 에러를 간결하게 전파한다.
타입 시스템
Trait과 제네릭 — Rust의 다형성
인터페이스 + 제네릭이 합쳐진 Rust의 추상화 도구
Trait은 Java의 인터페이스와 비슷하지만 더 강력하다. 제네릭과 결합하면 컴파일 타임에 타입이 확정되는(monomorphization) 제로 코스트 추상화가 가능하다.
Enum, Option, Result — Rust의 대수적 데이터 타입
null 없는 세계를 만드는 타입 시스템
Rust에는 null이 없다. 대신 Option<T>이 값의 부재를, Result<T, E>가 연산의 실패를 타입으로 표현한다. enum이 데이터를 담을 수 있기 때문에 가능한 설계다.
Box, Rc, Arc, RefCell — 스마트 포인터 가이드
소유권 규칙을 유연하게 우회하는 도구들
소유권 규칙만으로 해결 안 되는 패턴(재귀 타입, 공유 소유권, 내부 가변성)이 있다. 스마트 포인터가 이 갭을 메운다.
동시성
스레드와 채널 — 소유권 기반 동시성
"메모리를 공유해서 통신하지 말고, 통신해서 메모리를 공유하라"
Rust의 소유권 시스템은 data race를 컴파일 타임에 차단한다. std::thread로 OS 스레드를 생성하고, mpsc 채널 또는 Arc<Mutex>로 데이터를 공유한다.
async/await — Rust의 비동기 프로그래밍
Future trait 기반, 런타임 선택이 자유로운 비동기 모델
Rust의 async/await는 Future trait을 컴파일러가 상태 머신으로 변환하는 제로 코스트 추상화다. 런타임(tokio, async-std)은 사용자가 선택한다.
실전 패턴
Rust로 만들 수 있는 것들 — 초급부터 상급까지 프로젝트 로드맵
Hello World 다음에 뭘 만들지 막막할 때
Rust 문법을 배웠는데 뭘 만들어야 할지 모르겠다면. 난이도별로 실제로 만들 수 있는 프로젝트를 정리했다. CLI 도구부터 웹 서버, 게임 엔진까지.
Rust로 CLI 도구 만들기
clap + serde로 빠르게 만드는 실전 커맨드라인 도구
Rust는 CLI 도구 제작에 특히 강하다. 싱글 바이너리로 컴파일되고, 시작 시간이 빠르며, clap/serde 생태계가 탄탄하다.
Rust → WASM — 브라우저에서 Rust 돌리기
wasm-pack + wasm-bindgen으로 JS에서 Rust 함수 호출하기
Rust는 WASM 타겟으로 컴파일하면 브라우저에서 네이티브 속도로 실행된다. wasm-bindgen이 JS ↔ Rust 간 타입 변환을 자동 처리한다.
FFI — Rust에서 C 라이브러리 호출하기
extern "C", bindgen, unsafe의 실전 사용법
Rust는 C ABI와 직접 호환된다. extern "C" 블록으로 C 함수를 선언하고 unsafe에서 호출한다. VOICEVOX Engine이 Core를 ctypes로 호출하는 것도 이 패턴의 역방향(Rust→C ABI 노출)이다.
Rubyist를 위한 Rust
변수와 불변성 — Ruby의 자유로운 재할당이 사라진 이유
let, mut, shadowing, const — Ruby 변수와 1:1 비교
Ruby에서 변수는 언제든 재할당할 수 있다. Rust는 기본이 불변이다. mut, shadowing, const의 차이를 Ruby 코드와 비교하며 정리했다.
타입 시스템 — 동적 타입의 자유를 포기하면 얻는 것
Ruby의 duck typing vs Rust의 정적 타입 추론
Ruby는 duck typing이다. "quack 하면 오리." Rust는 컴파일 타임에 모든 타입을 결정한다. 추론이 강력해서 대부분 직접 쓸 필요는 없지만, 한 번 정해지면 절대 안 바뀐다.
함수와 메서드 — def가 fn이 되면 뭐가 달라지는가
반환 타입, 세미콜론, 그리고 Ruby와 같은 "마지막 식이 반환값" 규칙
Ruby의 def → Rust의 fn. 인자 타입과 반환 타입을 명시해야 하고, 세미콜론 하나로 반환값 여부가 결정된다. 그 외에는 Ruby와 생각보다 비슷하다.
구조체와 impl — Ruby의 class가 Rust에서 두 조각으로 나뉜다
struct로 데이터, impl로 메서드, trait로 다형성
Ruby의 class는 데이터와 메서드를 한 곳에 묶는다. Rust는 struct(데이터)과 impl(메서드)로 분리하고, 상속 대신 trait으로 공통 행위를 정의한다.
Enum과 패턴 매칭 — Symbol과 case/when의 강력한 진화판
Rust의 enum은 데이터를 담을 수 있다 — Ruby에는 없는 개념
Ruby의 Symbol이나 상수 그룹에 해당하는 Rust의 enum은 각 변형(variant)에 데이터를 담을 수 있다. match는 case/when의 강화판인데, 모든 케이스를 빠짐없이 처리해야 한다.
Option<T> — nil이 사라진 세계에서 살아남기
Ruby의 nil과 &. 연산자가 Rust에서는 어떻게 바뀌는가
Ruby의 nil은 어디서든 튀어나온다. Rust에는 nil이 없다. 값이 없을 수 있으면 Option<T>을 써야 하고, 컴파일러가 None 처리를 강제한다.
Result와 에러 처리 — begin/rescue가 사라진 자리
예외 대신 반환값으로 에러를 처리하는 Rust의 방식
Ruby는 예외를 던지고 rescue로 잡는다. Rust는 예외가 없다. 대신 Result<T, E>를 반환하고, ? 연산자로 에러를 전파한다.
이터레이터와 클로저 — Rubyist가 가장 편하게 느끼는 영역
select/map/reduce가 filter/map/fold로 바뀌었을 뿐
Ruby의 Enumerable 메서드가 거의 그대로 Rust에 있다. 이름만 약간 다르고 체이닝 패턴도 같다. Rubyist가 Rust에서 가장 빠르게 적응하는 부분.
String vs &str — Ruby에는 없는 문자열의 두 얼굴
소유하는 문자열과 빌리는 문자열의 차이
Ruby에서 문자열은 String 하나다. Rust에는 String(소유)과 &str(빌림) 두 종류가 있다. 처음에 혼란스럽지만, 소유권 개념과 연결되는 핵심.
컬렉션 — Array와 Hash가 Vec과 HashMap이 되면
타입이 고정된 세계의 배열과 해시맵
Ruby의 Array와 Hash가 Rust에서는 Vec<T>와 HashMap<K, V>이 된다. 가장 큰 차이는 한 가지 타입만 담을 수 있다는 것.
소유권 — Ruby의 GC가 해주던 일을 직접 하기
Rubyist가 가장 어려워하는 Rust의 핵심 개념
Ruby에서는 GC가 메모리를 알아서 정리한다. Rust에서는 소유권 규칙이 GC를 대체한다. 값을 넘기면 원본이 사라지는 move 개념이 핵심이다.
Cargo — Bundler + Rake가 하나로 합쳐진 것
Gemfile → Cargo.toml, bundle exec → cargo run
Ruby 생태계에서 Bundler(의존성)와 Rake(빌드/태스크)를 따로 쓰지만, Rust는 Cargo 하나로 전부 한다. 프로젝트 생성, 빌드, 테스트, 의존성 관리, 배포까지.