Rust 기초 강좌 #1 Rust란: 배우는 이유, rustup 설치와 cargo 첫 사용
요즘 새로 나오는 개발 도구의 소개 글에는 “Rust로 만들었다"는 문장이 유난히 자주 보입니다. 파이썬 패키지 관리자 uv, 검색 도구 ripgrep 같은 CLI 도구들이 그렇고, 리눅스 커널과 Windows, Android의 일부 코드도 Rust로 쓰이고 있습니다. 이 시리즈는 그 Rust를 바닥부터 배우는 기초 9편입니다. 변수와 타입에서 시작해 이 언어의 심장인 소유권과 빌림을 넘고, 구조체와 열거형, 에러 처리, 컬렉션과 이터레이터, 트레이트와 제네릭을 거쳐 수명과 모듈까지 올라가겠습니다. 프로그래밍이 처음인 분보다는, 파이썬이나 자바스크립트 같은 언어를 하나 이상 다뤄 본 개발자를 독자로 전제합니다.
Rust가 해결한 문제: 안전과 성능은 골라야 했다 #
Rust 이전의 언어들은 메모리 관리에서 둘 중 하나를 골라야 했습니다.
- 가비지 컬렉터(GC)에 맡기는 쪽: 파이썬, 자바스크립트, Go가 이쪽입니다. 개발자가 메모리를 신경 쓰지 않아도 되지만, 런타임이 대신 일하는 비용과 GC가 개입하는 순간의 지연을 감수합니다.
- 개발자가 직접 관리하는 쪽: C와 C++가 이쪽입니다. 성능은 최대치지만, 해제한 메모리를 다시 쓰거나(use-after-free) 경계를 넘어 읽는 실수가 통째로 개발자 책임입니다. Microsoft와 Chrome 팀이 각각 자사 보안 취약점을 분석했을 때, 약 70%가 이런 메모리 버그였다는 결과는 유명합니다.
Rust의 답은 제3의 길입니다. 메모리를 누가 언제 해제할지를 컴파일 타임에 검사합니다. 런타임에 GC가 도는 것이 아니라, 컴파일러가 코드를 보고 “이 값은 이 지점에서 해제된다"를 미리 확정합니다. 그래서 C 수준의 성능을 내면서도 메모리 버그 클래스가 컴파일 단계에서 걸러집니다. 이 검사의 규칙이 3편에서 다룰 소유권(ownership)입니다.
물론 대가가 있습니다. 소유권 규칙을 어긴 코드는 컴파일 자체가 되지 않아서, 처음 몇 주는 “컴파일러와 싸운다"는 느낌을 받게 됩니다. 이 강좌의 목표는 그 싸움을 최대한 짧게 끝내는 것입니다. 규칙의 이유를 이해하면, 컴파일러는 적이 아니라 배포 전에 버그를 잡아 주는 리뷰어가 됩니다.
설치: rustup 한 줄이면 됩니다 #
Rust의 공식 설치 도구는 rustup입니다. 컴파일러(rustc), 빌드 도구(cargo), 문서까지 한 번에 설치하고, 이후 버전 관리도 담당합니다.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shmacOS와 리눅스 기준이고, Windows는 rustup 공식 사이트에서 rustup-init.exe를 받아 실행합니다. 설치가 끝나면 두 명령으로 확인합니다.
rustc --version
cargo --versionRust는 6주마다 새 안정판이 나오고 rustup update 한 줄로 갱신합니다. 버전이 빨리 오르는 대신 하위 호환이 엄격해서, 버전 차이로 예제가 깨질 걱정은 거의 없습니다. 이 강좌는 현행 표준인 2024 에디션 기준으로 진행합니다.
cargo: 프로젝트의 시작과 끝 #
실무에서 rustc를 직접 부를 일은 거의 없습니다. 프로젝트 생성, 빌드, 실행, 의존성 관리를 전부 cargo가 담당합니다.
cargo new hello
cd hello
cargo runcargo new가 만드는 구조는 두 개뿐입니다.
hello/
├── Cargo.toml ← 패키지 정보와 의존성 선언
└── src/
└── main.rs ← 소스 코드 진입점[package]
name = "hello"
version = "0.1.0"
edition = "2024"명령은 셋만 기억하면 시작할 수 있습니다. cargo run은 빌드하고 실행, cargo build는 빌드만, 그리고 cargo check는 실행 파일을 만들지 않고 컴파일 검사만 합니다. Rust는 컴파일 에러를 자주 보는 언어라서, 코드를 고칠 때마다 cargo check로 빠르게 확인하는 것이 기본 리듬이 됩니다.
첫 프로그램, 그리고 첫 컴파일 에러 #
fn main() {
let name = "러스트";
println!("안녕하세요, {name}!");
}fn main이 진입점이고, println!의 느낌표는 함수가 아니라 매크로라는 표시입니다. 여기까지는 다른 언어와 비슷합니다. Rust다운 부분을 보려면 일부러 에러를 하나 내 보겠습니다.
fn main() {
let count = 1;
count = 2; // 컴파일 에러
}error[E0384]: cannot assign twice to immutable variable `count`
--> src/main.rs:3:5
|
2 | let count = 1;
| ----- first assignment to `count`
3 | count = 2;
| ^^^^^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable: `mut count`let으로 선언한 변수는 기본이 불변이라는 것이 첫 번째 규칙인데, 지금 주목할 것은 에러 메시지 자체입니다. 어디가 문제인지, 왜 문제인지, 어떻게 고치면 되는지(help 줄)까지 알려 줍니다. Rust 학습의 절반은 이 메시지를 읽는 습관을 들이는 것입니다. 에러 코드가 궁금하면 rustc --explain E0384로 상세한 설명과 예제까지 볼 수 있습니다.
정리 #
- Rust는 GC 없이 메모리 안전을 보장하는 언어입니다. 해제 시점을 런타임이 아니라 컴파일 타임에 확정하는 소유권 규칙이 핵심이고, 그래서 C 수준의 성능과 메모리 버그 차단을 동시에 얻습니다.
- 대가는 학습 곡선입니다. 규칙을 어긴 코드는 컴파일이 되지 않지만, 그만큼 배포 후 크래시가 컴파일 에러로 앞당겨집니다.
- 설치는 rustup 한 줄, 프로젝트는 cargo가 전부 담당합니다.
cargo new,cargo run,cargo check세 명령이 기본 리듬입니다. - 에러 메시지는 원인과 수정 방법까지 담고 있습니다.
rustc --explain과 함께, 메시지를 정독하는 습관이 가장 빠른 학습 경로입니다. - 다음 편에서는 변수와 타입을 다룹니다. 불변이 기본인
let, 섀도잉, 그리고 함수가 표현식으로 끝나는 Rust 특유의 문법을 살펴보겠습니다.