[Chapter 5-1] Rust 구조체 정의와 생성

hwwwa·2021년 10월 28일
0

🦀 Rust

목록 보기
11/25

구조체 정의와 초기화

구조체는 튜플과 유사하게 구성요소들이 각자 다른 타입을 지닐 수 있습니다. 하지만 튜플과는 달리 각 구성요소들을 명명할 수 있어 값이 의미하는 바를 명확하게 인지할 수 있습니다. 구조체 내의 특정 요소 데이터 명세를 기술하거나 접근 시 순서에 의존할 필요가 없어 튜플보다 유연하게 다룰 수 있습니다.

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

구조체 중괄호 안에서는 필드(field)라 불리는 각 구성요소들의 타입과 접근할 수 있는 이름을 정의합니다.

정의한 구조체를 사용하려면 각 필드의 값을 명세한 인스턴스를 생성해야 합니다. 구조체를 정의할 때 필드들의 순서가 정의한 필드의 순서와 같을 필요는 없습니다.

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

인스턴스의 필드 값을 변경하고 싶다면 인스턴스가 변경 가능(mutable) 해야합니다.

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");

아래의 코드는 사용자의 이메일과 이름을 받아 User 구조체의 인스턴스를 반환하는 함수입니다.

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
        active: true,
        sign_in_count: 1,
    }
}

구조체 필드와 동일한 이름으로 함수 매개변수의 이름을 지정하는 것은 합리적이지만, 필드 이름과 변수를 반복해야하는 것은 비효율적입니다. 위의 코드를 더 간단하게 변경할 수 있습니다.

변수명이 필드명과 같을 때 간단하게 필드 초기화하기

앞서 살펴본 코드를 축약하기 위해 아래와 같이 필드 초기화 축약법(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"),
    ..user1
};

이름이 없고 필드마다 타입은 다르게 정의 가능한 튜플 구조체

구조체명을 통해 의미를 부여할 수 있으나 필드의 타입만 정의할 수 있고 명명은 할 수 없는 튜플 구조체라 불리는 튜플과 유사한 형태의 구조체를 정의할 수 있습니다.

일반적인 구조체 정의 방법과 같이 struct 키워드를 통해 정의 가능합니다. 튜플 타입 정의는 키워드 뒤에서 이루어집니다.

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

구조체 내의 타입이 모두 동일하지만 다른 튜플 구조체이기 때문에 blackorigin이 서로 다른 타입임을 유의해야합니다.

필드가 없는 유사 유닛 구조체

어떠한 필드도 없는 구조체 역시 정의 가능합니다. 이는 유닛타입인 ( ) 와 비슷하게 동작하며, 유사 유닛 구조체(unit-like structs)라 불립니다. 유사 유닛 구조체는 특정 타입에 트레잇(trait)을 구현해야하지만 타입 자체게 데이터를 저장하지 않는 경우에 유용합니다.

구조체 데이터의 소유권

첫 예제였던 User 구조체 정의에서는 &str 문자 슬라이스 타입 대신 String 타입을 사용했습니다. 이는 의도적으로 구조체 전체가 유효한 동안 구조체가 그 데이터를 소유하게 하고자함입니다.

구조체가 소유권이 없는 데이터의 참조를 저장할 수는 있지만, 라이프타임의 사용을 전제로 합니다. 라이프타임은 구조체가 존재하는 동안 참조하는 데이터를 계속 존재할 수 있도록 합니다. 라이프타임을 사용하지 않고 참조를 저장하고자 하면 아래와 같은 일이 발생합니다.

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

0개의 댓글