튜플 및 구조체를 사용하여 데이터 컬렉션 정의

완료됨

이 단원에서는 데이터 컬렉션 또는 복합 데이터 작업에 유용한 두 가지 데이터 형식인 튜플과 구조체를 살펴봅니다.

튜플

튜플은 하나의 복합 값으로 수집되는 다양한 형식의 값을 그룹화한 것입니다. 튜플의 개별 값을 요소라고 합니다. 그 값은 괄호 (<value>, <value>, ...)로 묶은 쉼표로 구분된 목록으로 지정합니다.

튜플에는 요소의 수와 동일한 고정 길이가 있습니다. 튜플이 선언된 후에는 크기가 커지거나 축소될 수 없습니다. 요소는 추가하거나 제거할 수 없습니다. 튜플의 데이터 형식은 요소의 데이터 형식 시퀀스로 정의됩니다.

튜플 정의

다음은 세 가지 요소가 있는 튜플의 예입니다.

// Tuple of length 3
let tuple_e = ('E', 5i32, true);

다음 표에서는 튜플의 각 요소에 대한 인덱스, 값, 데이터 형식을 보여줍니다.

요소 데이터 형식
0 E char
1 5 i32
2 true bool

이 튜플의 형식 서명은 세 가지 요소의 형식 시퀀스 (char, i32, bool)로 정의됩니다.

튜플의 요소에 액세스합니다.

튜플의 요소는 0부터 시작하는 인덱스 위치에서 액세스할 수 있습니다. 이 프로세스를 튜플 인덱싱이라고 합니다. 튜플의 요소에 액세스할 때 구문 <tuple>.<index>을 사용합니다.

다음 예제는 인덱싱을 사용하여 튜플의 요소에 액세스하는 방법입니다.

// Declare a tuple of three elements
let tuple_e = ('E', 5i32, true);

// Use tuple indexing and show the values of the elements in the tuple
println!("Is '{}' the {}th letter of the alphabet? {}", tuple_e.0, tuple_e.1, tuple_e.2);

이 예제는 다음 출력을 보여줍니다.

Is 'E' the 5th letter of the alphabet? true

Rust Playground에서 이 예제를 살펴볼 수 있습니다.

튜플은 여러 형식을 단일 값으로 결합하려는 경우에 유용합니다. 튜플은 많은 값을 포함할 수 있으므로 함수에서 튜플을 사용하여 여러 값을 반환할 수 있습니다.

구조체

구조체는 다른 형식으로 구성된 형식입니다. 구조체의 요소를 필드라고 합니다. 튜플처럼 구조체의 필드에도 서로 다른 데이터 형식이 있을 수 있습니다. 구조체 형식의 큰 이점은 값의 의미를 알 수 있도록 각 필드의 이름을 지정할 수 있다는 것입니다.

Rust 프로그램에서 구조체를 사용하려면 먼저 이름으로 구조체를 정의하고 각 필드에 대한 데이터 형식을 지정합니다. 그런 다음 다른 이름으로 구조체의 인스턴스를 만듭니다. 인스턴스를 선언할 때 필드의 특정 값을 제공합니다.

Rust는 클래식 구조체, 튜플 구조체 및 단위 구조체의 세 가지 구조체 형식을 지원합니다. 이러한 구조체 형식은 데이터를 그룹화하고 작업하는 다양한 방법을 지원합니다.

  • 클래식C 구조체가 가장 일반적으로 사용됩니다. 구조체의 각 필드에는 이름과 데이터 형식이 있습니다. 클래식 구조체를 정의한 후에는 구문 <struct>.<field>을 사용하여 구조체의 필드에 액세스할 수 있습니다.
  • 튜플 구조체는 클래식 구조체와 유사하지만 필드에 이름이 없습니다. 튜플 구조체의 필드에 액세스하려면 튜플을 인덱싱할 때와 동일한 구문 <tuple>.<index>을 사용합니다. 튜플처럼 튜플 구조체의 인덱스 값은 0부터 시작합니다.
  • 단위 구조체는 표식으로 가장 일반적으로 사용됩니다. Rust의 특성 기능에 대해 알아볼 때 이러한 구조체가 유용한 이유를 자세히 알아보겠습니다.

다음 코드는 구조체 형식의 세 가지 종류에 대한 예제 정의를 보여줍니다.

// Classic struct with named fields
struct Student { name: String, level: u8, remote: bool }

// Tuple struct with data types only
struct Grades(char, char, char, char, f32);

// Unit struct
struct Unit;

구조체 정의

구조체를 정의하려면 구조체 이름 뒤에 struct 키워드를 입력합니다. 그룹화 데이터의 중요한 특성을 설명하는 구조체 형식의 이름을 선택합니다. 지금까지 사용한 명명 규칙과 달리 구조체 형식의 이름은 대문자로 시작합니다.

구조체 형식은 종종 Rust 프로그램에서 main 함수 및 기타 함수 밖에 정의됩니다. 따라서 구조체 정의의 시작은 왼쪽 여백에서 들여쓰기되지 않습니다. 정의의 내부 부분만 들여쓰기되어 데이터 구성 방식을 표시합니다.

클래식 구조체

함수와 마찬가지로 클래식 구조체의 본문은 중괄호 {} 안에 정의됩니다. 클래식 구조체의 각 필드에는 구조체 내에서 고유한 이름이 지정됩니다. 각 필드의 형식은 구문 : <type>을 통해 지정됩니다. 클래식 구조체의 필드는 쉼표로 구분된 목록 <field>, <field>, ...으로 지정됩니다. 클래식 구조체 정의는 세미콜론으로 끝나지 않습니다.

// Classic struct with named fields
struct Student { name: String, level: u8, remote: bool }

클래식 구조체 정의의 이점은 이름으로 구조체 필드의 값에 액세스할 수 있다는 것입니다. 필드 값에 액세스하려면 구문 <struct>.<field>을 사용합니다.

튜플 구조체

튜플처럼 튜플 구조체의 본문도 괄호 () 안에 정의됩니다. 괄호는 구조체 이름 바로 다음에 옵니다. 구조체 이름과 여는 괄호 사이에 공백이 없습니다.

튜플과 달리 튜플 구조체 정의에는 각 필드의 데이터 형식만 포함됩니다. 튜플 구조체의 데이터 형식은 쉼표로 구분된 목록 <type>, <type>, ...으로 지정됩니다.

// Tuple struct with data types only
struct Grades(char, char, char, char, f32);

구조체 인스턴스화

구조체 형식을 정의한 후에 형식의 인스턴스를 만들고 각 필드의 값을 지정하여 구조체를 사용합니다. 필드 값을 설정할 때 정의된 순서와 동일한 순서로 필드를 지정할 필요가 없습니다.

다음 예제에서는 Student 및 Grades 구조체 형식에 대해 만든 정의를 사용합니다.

// Instantiate classic struct, specify fields in random order, or in specified order
let user_1 = Student { name: String::from("Constance Sharma"), remote: true, level: 2 };
let user_2 = Student { name: String::from("Dyson Tan"), level: 5, remote: false };

// Instantiate tuple structs, pass values in same order as types defined
let mark_1 = Grades('A', 'A', 'B', 'A', 3.75);
let mark_2 = Grades('B', 'A', 'A', 'C', 3.25);

println!("{}, level {}. Remote: {}. Grades: {}, {}, {}, {}. Average: {}", 
         user_1.name, user_1.level, user_1.remote, mark_1.0, mark_1.1, mark_1.2, mark_1.3, mark_1.4);
println!("{}, level {}. Remote: {}. Grades: {}, {}, {}, {}. Average: {}", 
         user_2.name, user_2.level, user_2.remote, mark_2.0, mark_2.1, mark_2.2, mark_2.3, mark_2.4);

문자열 리터럴을 문자열 형식으로 변환

구조체 또는 벡터와 같은 다른 데이터 구조 내에 저장된 문자열 데이터는 문자열 리터럴 참조(&str)에서 String 형식으로 변환되어야 합니다. 해당 변환을 수행하려면 표준 String::from(&str) 메서드를 사용합니다. 이 예제에서 이 메서드를 사용하는 방법에 주목하세요.

// Classic struct with named fields
struct Student { name: String, level: u8, remote: bool }
...
let user_2 = Student { name: String::from("Dyson Tan"), level: 5, remote: false };

값을 할당하기 전에 형식을 변환하지 않으면 컴파일러에서 오류가 발생합니다.

error[E0308]: mismatched types
  --> src/main.rs:24:15
   |
24 |         name: "Dyson Tan",
   |               ^^^^^^^^^^^
   |               |
   |               expected struct `String`, found `&str`
   |               help: try using a conversion method: `"Dyson Tan".to_string()`

error: aborting due to previous error

컴파일러는 .to_string() 함수를 사용하여 변환할 수 있다고 제안합니다. 이 예제에서는 String::from(&str) 메서드를 사용합니다.

Rust Playground에서 예제 코드와 상호 작용할 수 있습니다.

지식 점검

다음 질문에 대답하여 배운 내용을 확인하세요. 각 질문에 대해 하나의 대답을 선택한 다음, 답변 확인을 선택합니다.

1.

Rust에서 tuple은 무엇인가요?

2.

Rust에서 클래식 구조체와 튜플 구조체의 주요 차이점은 무엇인가요?