조용한 담장

Rust Using Structs to Structure Related Data - Quick Reference 본문

Rust

Rust Using Structs to Structure Related Data - Quick Reference

iosroid 2026. 1. 2. 12:23

5. Using Structs to Structure Related Data

이 글은 Rust 공식 문서 5장(Using Structs to Structure Related Data)의 내용을 기반으로 빠르게 훑어볼 수 있도록 정리한 요약본입니다.

5.1. Defining and Instantiating Structs

https://doc.rust-lang.org/book/ch05-01-defining-structs.html

핵심 개념 및 코드 스니핏

  1. 정의 (Definition): struct 키워드로 필드와 타입을 묶음.
struct User {
    username: String,
    email: String,
    active: bool,
}
  1. 인스턴스화 (Instantiation): 정의된 키에 값을 할당 (순서 무관).
let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
};
  1. 가변성 (Mutability): 인스턴스 전체가 mut여야 필드 변경 가능.
let mut user1 = User { /* ... */ };
user1.email = String::from("another@example.com"); // 가능
// let user2 = User { ... }; user2.email = ...; // 불가능 (컴파일 에러)
  1. 필드 초기화 축약 (Field Init Shorthand): 변수명과 필드명이 같으면 생략.
fn build(email: String, username: String) -> User {
    User {
        email,    // email: email 과 동일
        username, // username: username 과 동일
        active: true,
    }
}
  1. 구조체 갱신 문법 (Struct Update Syntax): ..instance로 나머지 필드 복사.
// user1의 active 등을 가져오고 email만 새로 설정
let user2 = User {
    email: String::from("new@example.com"),
    ..user1 
};
// 주의: String 같은 힙 데이터 필드가 user1에서 user2로 이동(Move)되면 user1은 재사용 불가
  1. 튜플 구조체 (Tuple Structs): 필드명 없는 구조체.
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
// black.0 으로 접근
  1. 유닛 구조체 (Unit-Like Structs): 필드가 없는 구조체 (트레이트 구현용).
struct AlwaysEqual;
let subject = AlwaysEqual;

통합 실전 예제

struct User {
    active: bool,
    username: String,
    email: String,
}

struct Color(i32, i32, i32); // 튜플 구조체
struct AlwaysEqual;          // 유닛 구조체

fn main() {
    // 1. 가변 인스턴스 생성
    let mut user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
    };

    // 2. 필드 값 변경
    user1.email = String::from("another@example.com");

    // 3. 구조체 갱신 문법 (Struct Update Syntax)
    // user1의 username(String) 소유권이 user2로 이동(Move)됨에 주의!
    let user2 = User {
        email: String::from("user2@example.com"),
        ..user1 
    };

    println!("User2 Email: {}", user2.email);
    println!("User2 Username: {}", user2.username); 
    // println!("{}", user1.username); // 컴파일 에러! (소유권 이동됨)
    println!("User1 Active: {}", user1.active); // Copy 타입(bool)은 여전히 사용 가능

    // 4. 튜플 구조체 사용
    let black = Color(0, 0, 0);
    println!("Black Color R: {}, G: {}, B: {}", black.0, black.1, black.2);

    // 5. 유닛 구조체 사용
    let _subject = AlwaysEqual;
}

5.1 Defining and Instantiating Structs - 테스트 코드(Rust Playground)
Gist


5.2. An Example Program Using Structs

https://doc.rust-lang.org/book/ch05-02-example-structs.html

핵심 개념 및 코드 스니핏

  1. 의미 부여 (Semantic Grouping): 개별 변수보다 구조체가 데이터의 관계를 명확히 함.
// Bad: fn area(width: u32, height: u32) -> u32
// Good:
struct Rectangle { width: u32, height: u32 }
fn area(rect: &Rectangle) -> u32 { ... }
  1. Debug 트레이트 파생 (Derive Debug): 구조체 출력을 위해 #[derive(Debug)] 추가.
#[derive(Debug)]
struct Rectangle { width: u32, height: u32 }
  1. 포맷팅 출력: {:?} 또는 {:#?} 사용.
let rect = Rectangle { width: 30, height: 50 };
println!("rect: {:?}", rect);   // 한 줄 출력
println!("rect: {:#?}", rect);  // 들여쓰기 출력 (Pretty Print)
  1. dbg! 매크로: 디버깅 정보를 stderr로 출력하고 값을 반환.
let width = dbg!(30 * 2); // 60을 출력하고 변수에 할당
dbg!(&rect); // 파일명, 라인번호, 값 출력

통합 실전 예제

#[derive(Debug)] // 구조체를 출력 가능하게 만듦
struct Rectangle {
    width: u32,
    height: u32,
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}

fn main() {
    let scale = 2;
    let rect1 = Rectangle {
        // dbg!는 값을 반환하므로 필드 할당 식 중간에 사용 가능
        width: dbg!(30 * scale), 
        height: 50,
    };

    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );

    // {:?} : 기본적인 Debug 출력
    println!("rect1 is {:?}", rect1);

    // {:#?} : 읽기 편한 Debug 출력
    println!("rect1 is {:#?}", rect1);

    // dbg! 매크로 활용 (소유권을 뺏기지 않으려 참조를 넘김)
    dbg!(&rect1);
}

5.2 An Example Program Using Structs - 테스트 코드(Rust Playground)
Gist


5.3. Methods

https://doc.rust-lang.org/book/ch05-03-method-syntax.html

핵심 개념 및 코드 스니핏

  1. 메서드 정의 (impl block): 함수가 아닌 구조체 컨텍스트 내의 메서드.
impl Rectangle {
    fn area(&self) -> u32 { /* ... */ }
}
  1. self 파라미터의 종류:
  • &self: 읽기 전용 (가장 많이 사용).
  • &mut self: 인스턴스 내부 값 변경 시 사용.
  • self: 소유권을 가져감 (메서드 종료 시 인스턴스 해제됨).
impl Rectangle {
    fn read(&self) {}       // 읽기
    fn change(&mut self) {} // 쓰기
    fn consume(self) {}     // 소유권 가져오기
}
  1. 연관 함수 (Associated Functions): self가 없는 함수. 주로 생성자(::new)로 사용.
impl Rectangle {
    fn square(size: u32) -> Self { // Self는 Rectangle의 별칭
        Self { width: size, height: size }
    }
}
// 호출: Rectangle::square(10);
  1. 다중 impl 블록: 코드를 분리하여 작성 가능.
impl Rectangle { fn area(&self) ... }
impl Rectangle { fn can_hold(&self) ... }

통합 실전 예제

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 1. 메서드: &self (Immutable Borrow)
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 2. 메서드: 다른 인스턴스와 상호작용
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }

    // 3. 메서드: 필드명과 동일한 이름 (Getter)
    fn width(&self) -> bool {
        self.width > 0
    }

    // 4. 메서드: &mut self (Mutable Borrow) - 상태 변경
    fn resize(&mut self, factor: u32) {
        self.width *= factor;
        self.height *= factor;
    }
}

// 별도의 impl 블록 (조직화를 위해 분리 가능)
impl Rectangle {
    // 5. 연관 함수: self가 없음 (생성자 역할)
    // 호출 시 :: 연산자 사용
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}

fn main() {
    let mut rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 10, height: 40 };
    let rect3 = Rectangle { width: 60, height: 45 };

    // 연관 함수 호출 (::)
    let sq = Rectangle::square(20); 

    println!("Area of rect1: {}", rect1.area()); // 자동 참조/역참조 기능으로 (&rect1).area()와 동일

    // 메서드와 필드 이름이 같을 경우, 괄호() 유무로 구분
    if rect1.width() {
        println!("Rect1 width exists: {}", rect1.width);
    }

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));

    // 상태 변경 메서드 호출
    rect1.resize(2);
    println!("Resized rect1: {:#?}", rect1);

    println!("Square constructed: {:?}", sq);
}

5.3 Methods - 테스트 코드(Rust Playground)
Gist

'Rust' 카테고리의 다른 글

Rust Understanding Ownership - Quick Reference  (0) 2025.12.29
Rust Common Programming Concepts - Quick Reference  (0) 2025.12.22
Comments