구조체는 튜플과 유사하게, 구성요소들이 각자 다른 타입을 지닐 수 있지만, 구성요소들을 각각 다르게 명명할 수 있어 값이 의미하는 바를 명확하게 할 수 있다. 구조체 내의 특정 요소 데이터 명세를 기술하거나, 접근할 때 순서에 의존할 필요가 없어 튜플보다 좀 더 유연하게 구성요소들을 다룰 수 있다.
구조체는 정의할 때는 struct
키워드를 먼저 입력하고 명명할 구조체 명을 입력하면 된다.
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
정의한 구조체는 아래와 같은 방식으로 사용할 수 있다.
let user = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
}
변경이 가능한 구조체 인스턴스에 들어있는 값을 바꾸고자 할 때는, 점(.) 표기법을 사용하여 특정 필드에 새 값을 할당할 수 있다.
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
}
user1.email= String::from("anotheremail@example.com");
변수명과 구조체의 필드명이 같다면, 필드 초기화 축약법(field init shorthand)을 이용할 수 있다. 이를 활용하면 구조체를 생성하는 함수를 더 간단히 작성할 수 있다.
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count:1,
}
}
존재하는 인스턴스에서 기존 값의 대부분은 사용하고, 몇몇 값만 바꿔 새로운 인스턴스를 정의하는 방법은 유용하다.
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
}
구조체 갱신법(struct update syntax)은 입력으로 주어진 인스턴스와 변화하지 않는 필드들을 명시적으로 할당하지 않기 위해 ..
구문을 하용한다.
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
}
구조체명을 통해 의미를 부여할 수 있으나 필드의 타입만 정의할 수 있고 명명은 할 수 없는, 튜플 구조체(tuple structx)라 불리는 튜프로가 유사한 형태의 구조체도 정의할 수 있다.
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
black
과 origin
은 서로 다른 타입이란 것을 유념해야 한다. 구조체 내의 타입이 모두 동일하더라도 각각의 구조체는 고유의 타입이기 때문이다.
어떤 필드도 없는 구조체 역시 정의할 수 있다. 이는 유닛 탕비인 ()
와 비슷하게 동작하고, 그때문에 유사 유닛 구조체(unit-like structs)라고 불린다. 유사 유닛 구조체는 특정한 타입의 트레잇(trait)을 구현해야하지만 타입 자체에 데이터를 저장하지 않는 경우 유용하다.
위에서 User
구조체 정의에서는, &str
문자 슬라이스 타입 대신 String
타입을 사용했다. 이는 의도적인 선택으로, 구조체 전체가 유효한 동안 구조체가 그 데이터를 소유하게 하고자 함이다.
구조체가 소유권이 없는 데이터의 참조를 저장할 수는 있지만, 라이프타임(lifetimes)의 사용을 전제로 한다. 라이프타임은 구조체가 존재하는 동안 참조하는 데이터를 계속 존재할 수 있도록 한다. 라이프타임을 사용하지 않을 경우 아래와 같은 일이 발생한다.
struct User {
username: &str,
email: &str,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: "someone@example.com",
username: "someusername123",
active: true,
sign_in_count:1,
};
}
다음과 같은 에러가 발생한다.
error[E0106]: missing lifetime specifier
-->
|
2 | username: &str,
| ^ expected lifetime parameter
error[E0106]: missing lifetime specifier
-->
|
3 | email: &str,
| ^ expected lifetime parameter
출처: https://rinthel.github.io/rust-lang-book-ko/ch05-01-defining-structs.html