it ·

러스트(Rust) 기초 문법 총정리: 변수부터 소유권까지 한 번에

반응형

 

러스트(Rust) 기초 문법 총정리: 변수부터 소유권까지 한 번에

Rust programming representative image
대표이미지(교체 가능): Rust/시스템 프로그래밍 분위기의 일반적인 개발 이미지입니다.

Rust는 “안전성(메모리 안전)”과 “성능(제로 코스트 추상화)”을 동시에 목표로 하는 시스템 프로그래밍 언어입니다. C/C++에서 자주 발생하는 메모리 오류를 컴파일 타임에 강하게 막아주기 때문에, 백엔드/임베디드/CLI/고성능 서버 등에서 점점 더 많이 사용됩니다.

이 글은 러스트를 처음 시작하는 분을 위해, “문법 + 실제 코드 예시” 중심으로 정리합니다. 단순 암기보다 왜 이렇게 쓰는지까지 이해할 수 있게 구성했어요.


1) Rust 프로젝트 시작: Cargo 기본

Rust의 공식 빌드 도구/패키지 매니저는 Cargo입니다. Rust를 한다 = Cargo를 쓴다, 라고 생각해도 됩니다.

프로젝트 생성

cargo new hello_rust
cd hello_rust
cargo run
  • src/main.rs: 실행 파일 엔트리
  • Cargo.toml: 의존성/프로젝트 설정

Hello World

fn main() {
    println!("Hello, Rust!");
}

2) 변수와 상수: let, mut, const

Rust에서 기본 변수는 불변(immutable)입니다. 즉, 실수로 값이 바뀌는 것을 기본적으로 막습니다. 바꾸려면 mut 키워드를 명시해야 합니다.

불변 변수 vs 가변 변수

fn main() {
    let x = 10;      // 불변
    // x = 20;        // ❌ 컴파일 에러

    let mut y = 10;  // 가변
    y = 20;          // ✅ OK

    println!("x={x}, y={y}");
}

상수(const)

상수는 반드시 타입을 명시해야 하고, 컴파일 타임에 결정되는 값이어야 합니다.

const MAX_USERS: u32 = 1000;

fn main() {
    println!("MAX_USERS={MAX_USERS}");
}

섀도잉(Shadowing)

Rust는 같은 이름을 let으로 다시 선언해 값을 “덮어쓰는” 섀도잉을 허용합니다. (mut로 바꾸는 것과 느낌이 다릅니다: “새 변수”로 다시 바꿔치기)

fn main() {
    let a = "10";
    let a = a.parse::().unwrap(); // 타입까지 바꿀 수 있음
    println!("a={a}");
}

3) 기본 타입: 숫자, bool, char, 문자열

숫자 타입

  • 정수: i8 i16 i32 i64 i128 isize, u8 u16 u32 u64 u128 usize
  • 실수: f32 f64
fn main() {
    let n: i32 = -10;
    let u: u32 = 10;
    let f: f64 = 3.14;
    println!("{n}, {u}, {f}");
}

bool / char

fn main() {
    let ok: bool = true;
    let c: char = '가'; // char는 유니코드 1글자
    println!("{ok}, {c}");
}

문자열: &str vs String

Rust 문자열은 입문 난이도가 높은 편입니다. 핵심만 잡으면 됩니다.

  • &str: 문자열 “슬라이스”, 보통 리터럴(고정) / 참조 형태
  • String: 힙에 저장되는 “가변 문자열”
fn main() {
    let s1: &str = "hello";           // 슬라이스(대개 불변)
    let mut s2: String = String::from("hi"); // 가변 String
    s2.push_str(" rust");
    println!("{s1} / {s2}");
}

4) 함수와 반환: fn, return, 표현식

Rust는 마지막 줄에 세미콜론(;)이 없으면 반환값이 됩니다. 이게 Rust 문법의 아주 중요한 감각입니다.

fn add(a: i32, b: i32) -> i32 {
    a + b  // ✅ 세미콜론 없음 = 반환
}

fn main() {
    let r = add(3, 4);
    println!("{r}");
}

조기 반환

fn safe_div(a: i32, b: i32) -> i32 {
    if b == 0 {
        return 0;
    }
    a / b
}

5) 조건문과 반복문: if, loop, while, for

if는 “표현식”이다

Rust에서 if는 값을 만들 수 있습니다.

fn main() {
    let score = 87;
    let grade = if score >= 90 { "A" } else { "B" };
    println!("grade={grade}");
}

loop / while / for

fn main() {
    let mut i = 0;

    loop {
        i += 1;
        if i == 3 { break; }
    }

    let mut j = 0;
    while j < 3 {
        j += 1;
    }

    for k in 0..3 {
        println!("k={k}");
    }
}

6) 컬렉션: 배열, 튜플, 벡터

배열(Array) - 고정 길이

fn main() {
    let arr: [i32; 3] = [1, 2, 3];
    println!("{}", arr[0]);
}

튜플(Tuple) - 서로 다른 타입 가능

fn main() {
    let t: (i32, &str, bool) = (10, "hi", true);
    let (a, b, c) = t; // 구조 분해
    println!("{a}, {b}, {c}");
}

벡터(Vec) - 가변 길이

fn main() {
    let mut v: Vec<i32> = vec![1, 2, 3];
    v.push(4);
    println!("{:?}", v);
}

7) 구조체(Struct)와 메서드(impl)

Rust에서 데이터 묶음은 구조체로 많이 다룹니다.

struct User {
    name: String,
    age: u32,
}

impl User {
    fn new(name: &str, age: u32) -> Self {
        Self { name: name.to_string(), age }
    }

    fn greet(&self) {
        println!("Hi, I'm {} ({})", self.name, self.age);
    }
}

fn main() {
    let u = User::new("Hong", 18);
    u.greet();
}

8) enum과 match: 러스트의 “필살기”

Rust의 enum은 단순 상수 집합이 아니라, “상태 + 값”을 함께 담는 강력한 타입입니다.

enum ResultState {
    Ok(i32),
    Err(String),
}

fn main() {
    let r = ResultState::Ok(200);

    match r {
        ResultState::Ok(code) => println!("success: {code}"),
        ResultState::Err(msg) => println!("fail: {msg}"),
    }
}

Option: null 대신 쓰는 표준 타입

fn get_first(v: &Vec<i32>) -> Option<i32> {
    if v.is_empty() { None } else { Some(v[0]) }
}

fn main() {
    let v = vec![10, 20];
    match get_first(&v) {
        Some(x) => println!("first={x}"),
        None => println!("empty"),
    }
}

9) 소유권(Ownership) 핵심만: 왜 Rust가 안전한가

Rust 입문에서 가장 중요한 개념이 소유권(ownership)입니다. 쉽게 말해 “값의 주인이 누구인지”를 컴파일러가 엄격하게 추적해서, 해제된 메모리를 또 쓰는 문제(use-after-free) 같은 위험을 막습니다.

이동(move)

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1이 s2로 이동(move)됨

    // println!("{}", s1); // ❌ s1 사용 불가
    println!("{}", s2);
}

복사(copy) - 간단 타입은 자동 복사

fn main() {
    let a = 10;
    let b = a; // i32는 Copy
    println!("{a}, {b}");
}

빌림(borrow) - 참조(&T)

fn print_len(s: &String) {
    println!("len={}", s.len());
}

fn main() {
    let s = String::from("hello");
    print_len(&s); // 빌려주기
    println!("{}", s); // 여전히 사용 가능
}

가변 참조(&mut T) 규칙

Rust는 동시 수정 경쟁을 막기 위해 가변 참조는 동시에 하나만 허용하는 규칙이 있습니다.

fn main() {
    let mut s = String::from("hi");
    let r = &mut s;
    r.push_str(" rust");
    println!("{r}");
}

10) 에러 처리: Result와 ? 연산자

Rust는 예외(Exception)를 던지는 대신, 보통 Result<T, E>로 에러를 반환합니다. 그리고 ? 연산자로 “에러면 바로 반환”을 깔끔하게 처리할 수 있습니다.

use std::fs;

fn read_file(path: &str) -> Result<String, std::io::Error> {
    let s = fs::read_to_string(path)?; // 에러면 바로 반환
    Ok(s)
}

fn main() {
    match read_file("Cargo.toml") {
        Ok(text) => println!("read ok: {} chars", text.len()),
        Err(e) => println!("read fail: {e}"),
    }
}

11) 모듈과 공개 범위: mod, pub

Rust는 기본적으로 “숨김(private)”이 기본값입니다. 외부에 노출하려면 pub이 필요합니다.

// lib.rs 예시

mod utils {
    pub fn hello() {
        println!("hello");
    }

    fn secret() {
        println!("secret");
    }
}

fn main() {
    utils::hello();
    // utils::secret(); // ❌ private
}

12) 입문자가 자주 막히는 포인트 (현실 체크)

  • &str vs String: “고정 참조 vs 가변 힙 문자열” 감각을 잡아야 합니다.
  • move/borrow: 값이 이동되는 순간과 참조로 빌리는 순간을 구분하세요.
  • match: 초반엔 길어 보이지만, 안정성과 가독성을 크게 올려줍니다.
  • 컴파일 에러: Rust는 에러 메시지가 친절한 편이라 “에러로 배우는 언어”로 접근하면 빨리 늡니다.

13) 마무리: 다음 단계 로드맵

여기까지가 “Rust 문법 입문”의 뼈대입니다. 다음 단계는 아래 순서로 추천합니다.

  1. 소유권 심화: 라이프타임(lifetime) 기초 맛보기
  2. 트레이트(trait): 인터페이스/다형성 감각
  3. 제네릭(generic): 타입 안전한 재사용 코드
  4. 비동기(async): tokio 기반 서버/CLI 확장
TIP
Rust는 “문법”보다 “규칙(소유권/빌림)”이 핵심입니다.
처음엔 답답해도, 규칙이 몸에 붙으면 코드 품질이 확 달라집니다.

관련 키워드 태그 (10개)

#Rust #러스트 #Rust기초 #Rust문법 #소유권 #Borrow #Cargo #시스템프로그래밍 #백엔드개발 #개발공부

Meta Description (160자 내외)

Rust 기초 문법을 변수/타입/함수/조건문/컬렉션/struct/enum/match부터 소유권·빌림·Result 에러 처리까지 예제로 정리한 입문 가이드.

반응형