구조체 (struct)
여러 값을 묶고 이름을 지어서 의미있는 묶음을 정의한 것
러스트에서 구조체의 구성 요소들은 튜플처럼 각각 다른 타입이 될 수 있으며, 각 요소에 이름을 붙일 수 있음
각 구성요소의 이름은 필드라고 부르고, 구조체를 사용하기 위해 실체화 시킨 것이 인스턴스
구조체는 각각이 고유한 타입으로 작동함
필드 값에 참조자를 저장하기 위해서는 라이프타임을 명시해야함
// 구조체 (양식)
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
// 인스턴스 (실체화)
let user1 = User {
active: true,
username: String::from("2mukee"),
email: String::from("2mukee@tistory.com"),
sign_in_count: 1,
};
user1.email = String::from("tlgns7386@gmail.com");
}
구조체 필드 초기화 축약법 (field init shorthand)
변수와 구조체 필드명이 같을 때 중복으로 입력하지 않는 방법
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn build_user(email: String, username: String) -> User {
User {
active: true,
username, // username: username과 동일
email, // email: email과 동일
sign_in_count: 1,
}
}
fn main() {
let email = String::from("2mukee@tistory.com");
let username = String::from("2mk");
let user = build_user(&email, &username);
}
구조체 업데이트 문법 (struct update syntax)
다른 인스턴스에서 대부분의 값을 유지한 채로 몇 개의 값만 바꿔 새로운 인스턴스를 생성하는 방법
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let user1 = User {
active: true,
username: String::from("2mukee"),
email: String::from("2mukee@tistory.com"),
sign_in_count: 1,
};
// 이 경우 user1의 username과 email을 사용할 경우 user1을 더이상 사용할 수 없음 (String이 user2로 이동하기 때문)
// 대신 스칼라 타입인 user1의 active와 sign_in_count만 사용할 경우 user1은 유효함
let user2 = User {
email: String::from("tlgns7386@gmail.com"),
..user1,
}
}
튜플 구조체 (tuple struct)
튜플과 유사한 형태의 구조체로, 구조체를 구성하는 필드에 이름을 붙이지 않고 타입만 적어넣은 형태
튜플 전체에 이름을 지어주거나 특정 튜플을 다른 튜플과 구분하고 싶은데 일반적인 구조체 형태로 만들면 너무 장황하거나 불필요한 경우 사용
struct Color(i32, i32, i32)
struct Point(i32, i32, i32)
fn main() {
let black = Color(0, 0, 0);
let start = Point(0, 0, 0);
}
유사 유닛 구조체 (unit-like struct)
필드가 아예 없는 구조체로 유닛타입과 비슷하게 동작하는 구조체
어떤 타입에 대해 트레이트를 구현하고 싶지만 타입 내부에 어떤 데이터를 저장할 필요는 없을 경우 유용
struct AlwaysEqual;
fn main() {
let subject = AlwaysEqual;
}
구조체를 매개변수로 보내기
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
// area 함수 호출 이후에도 rect1을 사용할 수 있도록 불변 참조자로 넘겨줌
println!("rectangle is {} quare pixels", area(&rect1));
}
fn area(rectangle: &Rectangle) -> u32 {
// 빌린 구조체 인스턴스의 필드에 접근
rectangle.width * rectangle.height
}
구조체 정보 출력하기
// 구조체의 디버깅 정보를 출력하기 위한 명시적인 동의
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle {
width: 3-,
height: 50,
};
// 러스트의 구조체에는 Display 구현체가 기본 제공되지 않아
// {:?} 키워드를 통해 디버깅 할 때만 출력되게 할 수 있다
println!("rect1 is {:?}", rect1); // { width: 30, height: 50 }
}
{:?} 대신 {:#?} 을 사용하면 읽기 편한 형태로 출력이 됨
dbg! 매크로
표현식의 소유권을 가져와서 코드에서 dbg! 매크로를 호출한 파일 및 라인 번호를 결괏값과 함께 출력하고 다시 소유권을 반환
디버그 시 유용한 정보들을 출력할 수 있음
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let scale = 2;
let rect1 = Rectangle {
width: dbg!(30 * scale), // [src/main.rs:10] 30 * scale = 60
height: 50,
};
// rect1의 소유권을 가져가지 않도록 참조자로 넘겨줌
dbg!(&rect1);
//[src/main.rs:15] &rect1 = Rectangle {
// width: 60,
// height: 50,
// }
}
메서드 문법
구조체 콘텍스트에 정의 되는 함수
구조체 내에 fn 키워드와 함수명으로 선언되고 매개변수와 반환 값을 가지고, 다른곳에서 호출될 때 실행됨
그러나 함수와 달리 첫 번째 매개변수가 항상 self임
self 매개변수는 메서드를 호출하고 있는 구조체 인스턴스를 나타냄
strcut Rectangle {
width: u32,
height: u32,
}
// 메서드 문법
// impl 블록 내 모든 것은 Rectangle 타입과 연관됨
// imple 블록은 나눠서 작성될 수 있음
impl Rectangle {
// (self: &Self)와 동일
// 메서드는 다른 매개변수와 마찬가지로 소유권을 가져올 수도, 지금처럼 불변으로 빌려올 수도, 가변으로 빌려올수도 있음
fn area(&self) -> u32 {
self.width * self.height
}
fn width(&self) -> bool {
self.width > 0
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
// ()를 붙혀 area 메서드의 실행을 의도. ()를 안붙히면 필드명으로 인식
println!("area {}, width is non zero {}", rect1.area(), rect1.width);
}
필드와 동일한 이름의 메서드를 만드는 경우는 해당 필드의 값을 가져오는 것 말고는 아무것도 하지 않는 경우가 대부분임
이를 getter라고 함
러스트는 다른 언어와 달리 구조체 필드에 대한 getter를 자동으로 만들지 않음
연관 함수 (associated function)
impl 블록 내에 구현된 모든 함수를 의미
작동하는데 해당 타입의 인스턴스가 필요하지 않다면 self를 첫 매개변수로 갖지 않는,
따라서 메서드가 아닌 연관 함수를 정의 할 수 있음
String::from 과 같은 함수가 연관 함수임
연관 함수는 구조체의 새 인스턴스를 반환하는 생성자로 자주 활용됨
연관 함수는 보통 new라고 명명되는데 러스트에서 new는 예약어가 아님
strcut Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}
fn main() {
let sq = Rectangle::square(3);
}'Programming > Rust' 카테고리의 다른 글
| 러스트 프로젝트 관리 (패키지, 크레이트, 모듈) (4) | 2025.09.01 |
|---|---|
| 러스트의 열거형과 패턴 매칭 (1) | 2025.08.24 |
| 러스트 소유권 이해하기 (7) | 2025.08.13 |
| 러스트의 일반적인 프로그래밍 개념 (6) | 2025.08.12 |
| 러스트 개념부터 설치, 기초 까지 (1) | 2025.08.11 |
