[C#] 여러 필드를 담을 수 있는 구조체, 튜플(Tuple)

2022. 3. 21. 22:11Languages/C#

 

 

 

튜플 (Tuple)

여러 필드를 담을 수 있는 구조체로, 역시 값 형식이다.

읽기 전용이 아니므로, 튜플 구성 필드의 값 변경이 가능하다.

구조체와 달리, 튜플은 형식 이름이 없다. 그렇기 때문에 즉석에서 사용할 복합 데이터 형식을 선언할 때 적합하다.

 

 

명명되지 않은 튜플(Unnamed Tuple)

다음과 같이 필드의 이름을 지정하지 않는 튜플을 명명되지 않은 튜플(Unnamed Tuple)이라고 한다.

var tuple = (123, 789);

 

튜플은 괄호 사이에 두 개 이상의 필드를 지정함으로써 만들어 진다. 위 예제처럼 생성한 경우,

C# 컴파일러는 자동적으로 123Item1이라는 필드에 담고, 789Item2라는 필드에 담는다.

var tuple = (123, 789);
Console.WriteLine($"{tuple.Item1}, {tuple.Item2}");  // 123, 789 출력

 

튜플이 System.ValueTuple 구조체를 기반으로 만들어지기 때문에 위와 같이 담긴다고 한다.

 

 

명명된 튜플(Named Tuple)

필드명:의 꼴로 필드의 이름을 지정하여 선언할 수도 있다.

var tuple = (Name:"DaekYou", Age: 25);
Console.WriteLine($"{tuple.Name}, {tuple.Age}");  // DaekYou, 25 출력

 

튜플 분해하기

다음과 같이 튜플을 분해할 수도 있다.

var tuple = (Name:"DaekYou", Age: 25);
var (name, age) = tuple;              // 분해
Console.WriteLine($"{name}, {age}");  // DaekYou, 25 출력

 

특정 필드를 무시하고 싶다면, _를 사용하면 된다.

var tuple = (Name:"DaekYou", Age: 25);
var (name, _) = tuple;                // Age 필드는 무시
Console.WriteLine($"{name}");         // DaekYou 출력

 

다음과 같이 여러 변수를 단 번에 생성하고 초기화하여 분해하는 것도 가능하다.

var (name, age) = ("DaekYou", 25);
Console.WriteLine($"{name}, {age}");         // DaekYou, 25 출력

 

 

switch 문 또는 switch 식의 분기 조건에 활용 해보기

튜플이 분해가 가능한 이유는 분해자(Deconstructor)를 구현하고 있기 때문이다.

분해자를 구현하고 있는 객체를 분해한 결과를 switch 문이나 switch 식의 분기 조건에 활용할 수 있다.

이것을 위치 패턴 매칭(Positional Pattern Matching)이라고 한다.

식별자나 데이터 형식이 아닌, 분해된 요소의 위치에 따라 값이 일치하는지를 판단하는 것이다.

var daekYou = (job:"학생", age: 17);

var discountRate = daekYou switch
             {
                 ("학생", int n) when n < 18 => 0.2,   // 학생 & 18세 미만
                 ("학생", _)                 => 0.1,   // 학생 & 18세 이상
                 ("일반", int n) when n < 18 => 0.1,   // 일반 & 18세 미만
                 ("일반", _)                 => 0.05,  // 일반 & 18세 이상
                 _ => 0,
             };

/*  C# 8.0 이상 버전에서만 사용 가능한 문법인 것 같다.  */

 

다음과 같이 메소드를 통해 활용할 수도 있다.

static double GetDiscountRate(object client)
{
    return cleint switch
             {
                 ("학생", int n) when n < 18 => 0.2,   // 학생 & 18세 미만
                 ("학생", _)                 => 0.1,   // 학생 & 18세 이상
                 ("일반", int n) when n < 18 => 0.1,   // 일반 & 18세 미만
                 ("일반", _)                 => 0.05,  // 일반 & 18세 이상
                 _ => 0,
             };
}


static void Main(string[] args)
{
    var alice   = (job:"학생", age: 17);
    var bob     = (job:"학생", age: 23);
    var charlie = (job:"일반", age: 15);
    var dave    = (job:"일반", age: 21);
    
    Console.WriteLine($"alice      :  {GetDiscountRate(alice)}");      // alice : 0.2
    Console.WriteLine($"bob        :  {GetDiscountRate(bob)}");        // bob : 0.1
    Console.WriteLine($"charlie    :  {GetDiscountRate(charlie)}");    // charlie : 0.1
    Console.WriteLine($"dave       :  {GetDiscountRate(dave)}");       // dave : 0.05
}

 

명명되지 않은 튜플과 명명된 튜플은 필드의 수와 형식이 같으면 할당 가능하다.

var unnamed = ("DaekYou", 25);                           // (string, int)
var named = (Name: "CoCo", Age: 1);                      // (string, int)

named = unnamed;
Console.WriteLine($"{named.Name}, {named.Age}");         // DaekYou, 25 출력

named = ("Rengar", 5);

unnamed = named;
Console.WriteLine($"{unnamed.Item1}, {unnamed.Item2}");  // Rengar, 5 출력

 

 

 

 

 

 

  • 이 글은 <이것이 C#이다> 책을 바탕으로 공부한 글입니다.
728x90
반응형