구조체(Struct)
각 티켓에 대해서는 세 가지 정보를 관리해야 합니다:
- 제목
- 설명
- 상태
이 정보들을 표현하기 위해 가장 먼저 String 타입을 떠올릴 수 있습니다. String은 Rust 표준 라이브러리에 정의된 타입으로, UTF-8 방식으로 인코딩된 텍스트를 담는 데 사용됩니다.
그런데 이 세 가지 정보를 하나의 덩어리, 즉 ’단일 엔티티(Entity)’로 묶으려면 어떻게 해야 할까요?
struct 정의하기
struct(구조체)를 사용하면 Rust에서 새로운 타입을 직접 정의할 수 있습니다.
struct Ticket {
title: String,
description: String,
status: String
}
구조체는 다른 프로그래밍 언어에서 흔히 접하는 클래스(Class)나 객체(Object)와 매우 비슷한 개념이라고 생각하시면 됩니다.
필드(Field) 정의하기
새로운 타입은 여러 다른 타입들을 **필드(Field)**로 결합하여 만들어집니다. 각 필드는 이름과 타입을 가져야 하며, 그 사이를 콜론 :으로 구분합니다. 필드가 여러 개라면 쉼표 ,로 각각을 나열합니다.
아래 Configuration 구조체 예시처럼, 모든 필드가 같은 타입일 필요는 없습니다:
struct Configuration {
version: u32,
active: bool
}
인스턴스화(Instantiation)
각 필드에 구체적인 값을 지정해 주면 구조체의 인스턴스(Instance)를 생성할 수 있습니다:
// 구문: <구조체이름> { <필드_이름>: <값>, ... }
let ticket = Ticket {
title: "Build a ticket system".into(),
description: "A Kanban board".into(),
status: "Open".into()
};
필드에 접근하기
마침표 . 연산자를 이용하면 구조체의 특정 필드 값에 접근할 수 있습니다:
// 필드 접근 let x = ticket.description;
메서드(Method)
**메서드(Method)**를 정의하면 구조체에 특정한 동작을 부여할 수 있습니다. Ticket 구조체를 예로 들어 보겠습니다:
impl Ticket {
fn is_open(self) -> bool {
self.status == "Open"
}
}
// 구문:
// impl <구조체이름> {
// fn <메서드_이름>(<매개변수>) -> <반환_타입> {
// // 메서드 본문
// }
// }
메서드는 함수와 매우 비슷하지만, 다음과 같은 두 가지 큰 차이점이 있습니다:
- 메서드는 반드시
impl블록 안에 정의해야 합니다. - 메서드는 첫 번째 매개변수로
self를 사용할 수 있습니다.self는 예약어(Keyword)로, 해당 메서드가 호출되는 구조체의 인스턴스 자신을 가리킵니다.
self
메서드가 첫 번째 매개변수로 self를 사용하는 경우, 메서드 호출 구문을 사용하여 호출할 수 있습니다:
// 메서드 호출 구문: <인스턴스>.<메서드_이름>(<매개변수>)
let is_open = ticket.is_open();
이것은 이전 장에서 u32 값에 대해 포화 산술 연산을 수행할 때 사용했던 것과 동일한 호출 방식입니다.
정적 메서드(Static Method)
만약 메서드의 첫 번째 매개변수가 self가 아니라면, 이를 **정적 메서드(Static Method)**라고 부릅니다.
struct Configuration {
version: u32,
active: bool
}
impl Configuration {
// `default`는 `Configuration`의 정적 메서드입니다.
fn default() -> Configuration {
Configuration { version: 0, active: false }
}
}
정적 메서드는 함수 호출 구문을 통해서만 호출할 수 있습니다:
// 함수 호출 구문: <구조체이름>::<메서드_이름>(<매개변수>)
let default_config = Configuration::default();
호출 방식의 유연성
첫 번째 매개변수로 self를 사용하는 일반 메서드 역시 함수 호출 구문으로 호출할 수 있습니다:
// 함수 호출 구문:
// <구조체이름>::<메서드_이름>(<인스턴스>, <매개변수>)
let is_open = Ticket::is_open(ticket);
함수 호출 구문을 쓰면 ticket이 메서드의 첫 번째 매개변수인 self로 전달된다는 점이 명확히 드러나지만, 코드가 다소 길어집니다. 따라서 특별한 이유가 없다면 메서드 호출 구문을 사용하는 것이 일반적입니다.
Exercise
The exercise for this section is located in 03_ticket_v1/01_struct