Rust 시작하기 | 메모리 안전한 시스템 프로그래밍 언어
이 글의 핵심
Rust 시작하기에 대한 실전 가이드입니다. 메모리 안전한 시스템 프로그래밍 언어 등을 예제와 함께 상세히 설명합니다.
들어가며
Rust란?
Rust는 원래 Mozilla에서 개발이 시작된 메모리 안전을 컴파일 타임(소스를 빌드할 때)에 잡는 시스템 프로그래밍 언어입니다. 힙 메모리는 소유권 규칙으로 다루는데, 값마다 열쇠가 하나라고 이해하시면 이후 글(소유권)로 자연스럽게 이어집니다.
특징:
- ✅ 메모리 안전: 컴파일 타임 보장
- ✅ 제로 코스트: 런타임(프로그램이 실제로 실행되는 때) 오버헤드 없음
- ✅ 동시성: 안전한 멀티스레딩
- ✅ 성능: C/C++ 수준
- ✅ 패키지 관리: Cargo 내장
Rust vs C++:
| 특징 | Rust | C++ |
|---|---|---|
| 메모리 안전 | 컴파일 타임 | 런타임 (선택) |
| Null 포인터 | 없음 (Option) | 가능 |
| 패키지 관리 | Cargo | CMake, vcpkg |
| 학습 곡선 | 가파름 | 매우 가파름 |
Cargo는 빌드·의존성·워크스페이스를 한 도구에 묶습니다. C++ 쪽에서는 CMake가 빌드 생성을, Conan·vcpkg가 라이브러리 공급을 나눠 담는 경우가 많고, npm·Go 모듈·Python pip·uv·Poetry와 “의존성 선언·락”을 대응시켜 보면 생태계 차이가 분명해집니다. C++ 빌드 시스템 완전 비교에서 언어별 철학을 더 깊게 다룹니다.
1. 설치
rustup 설치
Windows:
- rustup.rs 다운로드
- 설치 프로그램 실행
Mac/Linux:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
설치 확인
rustc --version
cargo --version
2. Hello World
프로젝트 생성
cargo new hello_rust
cd hello_rust
src/main.rs
fn main() {
println!("Hello, Rust!");
}
실행
cargo run
3. Cargo
프로젝트 구조
hello_rust/
├── Cargo.toml
├── Cargo.lock
└── src/
└── main.rs
Cargo.toml
[package]
name = "hello_rust"
version = "0.1.0"
edition = "2021"
[dependencies]
명령어
cargo new project_name # 프로젝트 생성
cargo build # 빌드
cargo run # 빌드 + 실행
cargo test # 테스트
cargo check # 빠른 체크
cargo build --release # 릴리스 빌드
4. 기본 문법
변수
fn main() {
// 불변 (기본)
let x = 5;
// x = 6; // 에러!
// 가변
let mut y = 5;
y = 6; // OK
// 타입 명시
let z: i32 = 10;
}
함수
fn add(a: i32, b: i32) -> i32 {
a + b // return 생략 가능
}
fn main() {
let result = add(10, 20);
println!("결과: {}", result);
}
5. 소유권 (Ownership)
기본 개념
Rust의 소유권(Ownership) 시스템은 메모리 안전성을 보장하는 핵심 개념입니다:
fn main() {
// String::from: 힙에 문자열 할당
let s1 = String::from("hello");
// 소유권 이동 (Move)
// s1의 소유권이 s2로 이동
// 이제 s1은 무효화됨 (더 이상 사용 불가)
let s2 = s1;
// println!("{}", s1); // 컴파일 에러!
// "value borrowed here after move"
// s1은 이미 소유권을 잃어서 사용할 수 없음
println!("{}", s2); // ✅ OK - s2가 소유권을 가짐
}
왜 이렇게 동작하나?
- C++에서는
s2 = s1후에도 둘 다 사용 가능 → 이중 해제(double free) 위험 - Rust는 소유권을 이동시켜 한 번에 하나만 소유 → 안전
참조 (Borrowing)
소유권을 이동하지 않고 빌려서 사용하는 방법입니다:
fn main() {
let s1 = String::from("hello");
// &s1: s1을 빌려줌 (소유권은 유지)
// 불변 참조 (Immutable Reference)
let len = calculate_length(&s1);
// s1은 여전히 유효 (소유권을 빌려줬다가 돌려받음)
println!("{} 길이: {}", s1, len); // ✅ s1 사용 가능
}
fn calculate_length(s: &String) -> usize {
// s는 참조일 뿐, 소유권이 없음
// 함수가 끝나도 s가 가리키는 데이터는 해제되지 않음
s.len()
}
// s가 스코프를 벗어나도 아무 일도 일어나지 않음 (소유권이 없으므로)
참조의 규칙:
- 여러 개의 불변 참조 가능 (읽기만)
- 가변 참조는 단 하나만 가능 (쓰기)
- 불변 참조와 가변 참조는 동시에 존재 불가
가변 참조
데이터를 수정하려면 가변 참조(Mutable Reference)를 사용합니다:
fn main() {
// mut: 변수를 가변으로 선언
let mut s = String::from("hello");
// &mut s: 가변 참조로 빌려줌
change(&mut s);
// 수정된 값 확인
println!("{}", s); // hello, world
}
fn change(s: &mut String) {
// s는 가변 참조이므로 수정 가능
// push_str: 문자열 끝에 추가
s.push_str(", world");
}
가변 참조의 제약:
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; // 컴파일 에러!
// "cannot borrow `s` as mutable more than once at a time"
// 가변 참조는 동시에 하나만 허용 → 데이터 경쟁 방지
r1.push_str(" world");
Rust의 안전성 보장:
- 동시에 여러 가변 참조 불가 → 데이터 경쟁 방지
- 참조가 있는 동안 원본 수정 불가 → 댕글링 포인터 방지
- 컴파일 타임에 모두 검사 → 런타임 오버헤드 없음
6. 데이터 타입
스칼라 타입
// 정수
let a: i8 = 127;
let b: i32 = 2147483647;
let c: u32 = 4294967295;
// 실수
let x: f32 = 3.14;
let y: f64 = 3.14159;
// 불리언
let t: bool = true;
let f: bool = false;
// 문자
let c: char = 'A';
let emoji: char = '😀';
복합 타입
// 튜플
let tup: (i32, f64, char) = (500, 6.4, 'A');
let (x, y, z) = tup;
println!("{}, {}, {}", x, y, z);
// 배열
let arr = [1, 2, 3, 4, 5];
let first = arr[0];
7. 실전 예제
예제: 간단한 계산기
fn main() {
println!("=== 계산기 ===");
let a = 10;
let b = 5;
println!("{} + {} = {}", a, b, add(a, b));
println!("{} - {} = {}", a, b, subtract(a, b));
println!("{} * {} = {}", a, b, multiply(a, b));
println!("{} / {} = {}", a, b, divide(a, b));
}
fn add(a: i32, b: i32) -> i32 { a + b }
fn subtract(a: i32, b: i32) -> i32 { a - b }
fn multiply(a: i32, b: i32) -> i32 { a * b }
fn divide(a: i32, b: i32) -> i32 { a / b }
정리
핵심 요약
- Rust: 메모리 안전한 시스템 언어
- Cargo: 빌드 도구 + 패키지 관리자
- 소유권: 메모리 안전성의 핵심
- 불변: 기본적으로 불변
- 성능: C/C++ 수준
다음 단계
- Rust 소유권
- Rust 구조체와 열거형
- Rust 에러 처리
관련 글
- C++ 초보자가 자주 하는 실수 Top 15 | 컴파일 에러부터 런타임 크래시까지
- C++와 Rust: 두 언어의 상호 운용성과 Memory Safety 논쟁의 실체 [#44-2]
- C++ vs Rust 완전 비교 | 소유권·메모리 안전성·에러 처리·동시성·성능 실전 가이드
- Rust 메모리 안전성 완벽 가이드 | 소유권·Borrow checker·수명·unsafe 실전
- Rust vs C++ 메모리 안전성 | 컴파일러 오류 차이 [#47-3]