← Rust 강의 목록으로
🦀
타입 시스템
타입 시스템 · 선수: 소유권 1~5강

11. 구조체 (named·tuple·unit 구조체)

구조체(struct) 는 여러 값을 의미 있는 이름으로 묶는 가장 기본적인 사용자 정의 타입입니다. Rust 는 세 가지 형태를 제공합니다 — 필드에 이름이 있는 named struct, 위치만 있는 tuple struct, 데이터가 없는 unit struct. 메서드는 impl 블록에서 따로 정의합니다.

Ruststructimpl메서드타입 시스템
소요 시간
약 1.5시간
난이도
📊 중급
선수 조건
🎯 소유권 1~5강
결과물
구조체(struct) 는 여러 값을 의미 있는 이름으로 묶는 가장 기본적인 사용자 정의 타입입니다. Rust 는 세 가지 형태를 제공합니다 — 필드에 이름이 있는 named struct, 위치만 있는 tuple struct, 데이터가 없는 unit struct. 메서드는 impl 블록에서 따로 정의합니다.

이 강의에서 배우는 것

  • 1named / tuple / unit struct 를 각각 정의한다
  • 2impl 블록으로 메서드와 연관 함수를 작성한다
  • 3struct update 문법(`..base`) 으로 필드를 일부만 바꾼 새 인스턴스를 만든다
  • 4`#[derive(Debug)]` 로 디버그 출력을 가능하게 한다
  • 5&self / &mut self / self 메서드 시그니처를 구분한다

소개

튜플 `(f64, f64)` 로 점을 표현할 수도 있지만, `.0` `.1` 로 접근하면 의도가 불분명합니다. struct 는 같은 데이터에 **의미 있는 이름** 을 붙여 코드의 자기 설명력을 끌어올립니다.

핵심 개념

1) 세 가지 형태

rust
// named — 필드명 있음
struct Point { x: f64, y: f64 }

// tuple struct — 필드명 없이 타입만
struct Color(u8, u8, u8);

// unit struct — 데이터 없음, 마커 용도
struct Marker;

2) impl — 메서드와 연관 함수

  • **메서드** — 첫 인자가 `self`, `&self`, `&mut self`. 인스턴스가 호출함
  • **연관 함수(associated function)** — self 가 없는 함수. `Type::func()` 으로 호출, 생성자 역할

3) self 의 세 가지 형태

수신자의미용도
&self불변 참조읽기 메서드
&mut self가변 참조쓰기 메서드
self소유권 가져감변환·소비 메서드

4) struct update 문법

`..base` 로 기존 인스턴스의 필드를 일부만 바꾼 새 인스턴스를 만들 수 있습니다.

핵심 예제

rust
#[derive(Debug, Clone)]
struct Point { x: f64, y: f64 }

impl Point {
    // 연관 함수 — 생성자
    fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }
    // 메서드 — &self 읽기
    fn distance_from_origin(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
    // 메서드 — &mut self 쓰기
    fn translate(&mut self, dx: f64, dy: f64) {
        self.x += dx;
        self.y += dy;
    }
}

fn main() {
    let mut p = Point::new(3.0, 4.0);
    println!("{}", p.distance_from_origin()); // 5.0
    p.translate(1.0, 1.0);
    println!("{:?}", p);                       // Point { x: 4.0, y: 5.0 }
}

tuple struct — 색상 같은 단순 wrapper:

rust
struct Color(u8, u8, u8);

fn main() {
    let red = Color(255, 0, 0);
    println!("R={}", red.0);
}

struct update 문법:

rust
#[derive(Debug)]
struct User { name: String, email: String, active: bool }

fn main() {
    let u1 = User { name: "홍길동".into(), email: "a@b.c".into(), active: true };
    let u2 = User { email: "new@b.c".into(), ..u1 };  // name, active 는 u1 에서 복사/이동
    println!("{:?}", u2);
}

자주 하는 실수

Q. println!("{}", p) 가 안 돼요

A. 기본 struct 는 Display 가 구현돼 있지 않습니다. `#[derive(Debug)]` 후 `{:?}` 또는 `{:#?}` 로 출력하거나, `impl fmt::Display` 를 직접 작성.

Q. &self 와 self 중 뭘 쓰나요?

A. **읽기는 &self, 쓰기는 &mut self, 인스턴스를 변환·소비(예: into_xxx) 하는 메서드는 self**. 이 세 가지가 명확히 구분된다는 점이 Rust 디자인의 정수.

Q. tuple struct 와 단순 tuple 의 차이가 뭐죠?

A. tuple struct 는 **이름이 있는 새 타입** 이라 컴파일러가 구분합니다. `Meters(f64)` 와 `Feet(f64)` 가 서로 호환 불가 → 타입 오용 컴파일 시 차단.

정리

  • named / tuple / unit 세 형태
  • impl 블록에 메서드와 연관 함수
  • self 의 세 형태 — &self / &mut self / self
  • `..base` 로 일부만 바꾼 새 인스턴스 생성

과제

  1. Rectangle 구조체에 area / perimeter 메서드를 작성
  2. User 구조체에 update_email(&mut self, new: String) 메서드를 작성하고 호출
  3. 단위를 헷갈리지 않게 tuple struct Meters(f64) / Feet(f64) 를 만들고 변환 함수 작성
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗