PHpullh
심층 가이드/Rust/객체지향

RUST · 심층 가이드

Rust 객체지향 완전 정리

구현 상속이 없는 언어에서 struct와 trait, enum을 조합해 캡슐화와 다형성, 불변 객체를 처음부터 다시 만들어 보는 20개 예제로 구성한 안내서입니다.

주제 20개 · 예제 코드 포함 · 최종 수정 2026-08-30 · 작성 pullh 편집팀

Rust에는 클래스가 없습니다. 데이터는 struct에, 동작은 impl 블록에 따로 놓이고, 구현 상속은 아예 제공되지 않습니다. 부모 클래스로 코드를 재사용하던 습관은 두 갈래로 나뉩니다. 공통 동작은 트레이트의 기본 구현으로, 공통 데이터는 필드로 품는 합성으로 갑니다. 가시성도 클래스 단위가 아니라 모듈 단위라서, pub을 붙이지 않은 필드는 같은 모듈 안에서만 보입니다.

기본 클래스 또는 구조체생성자와 초기화를 보면 new가 언어 기능이 아니라 그냥 관례상의 연관 함수라는 점이 드러납니다. 인터페이스 또는 trait에서 계약을 분리한 뒤 합성으로 기능 묶기로 상속의 빈자리를 메우고, 다형성에서 제네릭의 정적 디스패치와 dyn Trait의 동적 디스패치를 비교합니다. 상태 표현은 열거형 상태 표현이 맡고, 마지막으로 변경 불가능 업데이트가 소유권과 불변성을 한데 묶습니다.

dyn Trait로 다형성을 만들다 보면 객체 안전성에 걸립니다. 제네릭 타입 매개변수를 받는 메서드나 Self를 반환하는 메서드가 트레이트에 하나라도 있으면 그 트레이트는 트레이트 객체로 만들 수 없습니다. Clone을 상위 트레이트로 요구했다가 컴파일이 막히는 경우가 여기 해당합니다. 해결책은 그런 메서드를 where Self: Sized로 떼어내거나, 애초에 트레이트를 객체용과 제네릭용으로 나누는 것입니다.

01기본 클래스 또는 구조체

Rust에서 기본 클래스 또는 구조체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 기본 클래스 또는 구조체
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 1 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

02생성자와 초기화

Rust에서 생성자와 초기화 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 생성자와 초기화
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

03인스턴스 메서드

Rust에서 인스턴스 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 인스턴스 메서드
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 3 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

04정적 메서드

Rust에서 정적 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 정적 메서드
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

05상속 또는 확장

Rust에서 상속 또는 확장 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 상속 또는 확장
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 5 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

06인터페이스 또는 trait

Rust에서 인터페이스 또는 trait 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 인터페이스 또는 trait
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

07캡슐화

Rust에서 캡슐화 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 캡슐화
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 7 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

08합성으로 기능 묶기

Rust에서 합성으로 기능 묶기 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 합성으로 기능 묶기
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

09팩터리 메서드

Rust에서 팩터리 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 팩터리 메서드
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 9 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

10열거형 상태 표현

Rust에서 열거형 상태 표현 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 열거형 상태 표현
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

11불변 데이터 객체

Rust에서 불변 데이터 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 불변 데이터 객체
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 11 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

12빌더 패턴

Rust에서 빌더 패턴 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 빌더 패턴
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

13다형성

Rust에서 다형성 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 다형성
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 13 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

14의존성 주입

Rust에서 의존성 주입 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 의존성 주입
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

15값 객체 비교

Rust에서 값 객체 비교 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 값 객체 비교
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 15 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

16저장소 객체

Rust에서 저장소 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 저장소 객체
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

17서비스 객체

Rust에서 서비스 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 서비스 객체
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 17 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

18DTO 매핑

Rust에서 DTO 매핑 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// DTO 매핑
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

19변경 불가능 업데이트

Rust에서 변경 불가능 업데이트 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 변경 불가능 업데이트
struct User { name: String, level: i32 }
fn main() {
    let user = User { name: "Ada".to_string(), level: 19 };
    println!("{}", user.name);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

20확장 스타일 동작

Rust에서 확장 스타일 동작 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

Rust code

// 확장 스타일 동작
#[derive(Debug, Clone)]
struct Profile { name: String, tags: Vec<String> }
fn main() {
    let profile = Profile { name: "Ada".to_string(), tags: vec!["rust".to_string()] };
    println!("{:?}", profile);
}
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

정리하며

  • 상속 대신 트레이트 기본 구현과 필드 합성으로 재사용을 설계합니다
  • new는 언어가 부르는 생성자가 아니라 관례일 뿐이라는 점을 기억합니다
  • 성능이 중요하면 제네릭, 이종 컬렉션이 필요하면 dyn Trait을 고릅니다
  • 트레이트 객체를 쓸 계획이면 제네릭 메서드와 Self 반환을 피합니다

더 깊이 들어가고 싶다면 Rust 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.