안녕하세요. 박민성입니다. 🤗
오늘은 C#에 튜플(Tuple)에 대해서 글을 쓰고자 합니다. 🤔
튜플을 Unity에서 많이 사용하기도 하고 작고 단순한 값을 묶을 때 성능상 좋으편이어서입니다.
1. 튜플이란?
튜플은 서로 다른 여러 값을 하나의 값처럼 묶어서 저장하거나 전달하는 문법입니다.
배열은 서로 같은 자료형들을 하나로 묶어서 저장하거나 전달하지만
튜플은 자료형이 달라도 하나로 묶어서 사용할 수 있습니다.
(int health, int mana) stats = (100, 50);
저는 약간 미니, 간단 버전 구조체? 느낌으로 사용 중입니다.
2. 튜플 변수 선언, 사용 방법
a. 타입 추론
var stats = (health: 100, mana: 50);
컴파일러가 값을 보고 튜플의 자료형을 알아냅니다.
b. 자료형 직접 작성
(int, int) stats = (100, 50);
이런식으로 타입 추론이 아닌 직접 자료형을 적어서 선언할 수 있습니다.
c. 자료형과 이름 함께 작성
(int health, int mana) stats = (100, 50);
가장 의미를 알아보기 쉬워서 많이 사용되는 선언 방법입니다.
여기서 c방법( 자료형과 이름 함께 작성 )으로 튜플을 작성 했을때
Debug.Log(stats.health);
Debug.Log(stats.mana);
이렇게 선언된 변수명을 통해서 튜플에 미리 함께 작성한 이름으로 사용할 수 있습니다.
하지만 a와 b는 자료형과 이름을 함께 작성하지 않았는데요.
그럼 튜플을 어떻게 사용할까용~? 🤔
Debug.Log(stats.Item1);
Debug.Log(stats.Item2);
이렇게 Item1, Item2로 사용할 수 있습니다.
(int health, int mana, int damege, int moveSpeed) 이렇게 늘어나면
Item3, Item4로 늘어난만큼 사용할 수 있습니다.
3. 튜플에 원형
저는 (int health, int mana) 이런 형태를 보면서 이게 내부적으로 어떻게 작동하는지 궁금했습니다.
찾아보니 지금 사용 중인 괄호에 자료형을 적어서 사용하는 방식은 내부적으로 ValueTuple와 똑같다는걸 알았습니다.
(int mana, int health) stats = (50, 100);
// 이건 똑같음
ValueTuple<int, int> stats = new ValueTuple<int, int>(50, 100);
현재 사용중인 튜플 문법은 ValueTuple을 더욱 간결하게 선언할 수 있도록 하는 것이 튜플 문법입니다.
튜플 문법은 컴파일러를 거치면 System.ValueTuple<int, int> 기반 타입을 사용하므로 실행 성능과 메모리 특성은
사실상 차이가 없습니다.
다만 튜플 문법은 요소에 이름을 정할 수 있는데요. 하지만 ValueTuple 선언 과정에서는 요소마다 이름을 정할 수 없는 것이 가장 큰 차이점입니다.
ValueTuple<int, int> rawStats = new(50, 100);
(int mana, int health) stats = rawStats;
Debug.Log(stats.mana);
Debug.Log(stats.health);
이렇게 ValueTuple을 선언하고 튜플 문법에 담아서 이름을 활용하는 것도 방법입니다.
4. Tuple과 ValueTuple의 차이
튜플을 찾아보다가 Tuple이라는걸 발견하게 되었습니다.
System.Tuple<T1, T2>
튜플 문법은 내부적으로 ValueTuple이지만 Tuple은 완전 다릅니다.
Tuple<int, int> tuple = Tuple.Create(50, 100);
ValueTuple<int, int> valueTuple = new(50, 100);
Tuple이랑 ValueTuple의 선언 방식입니다.
Tuple이랑 ValueTuple은 모두 여러 값을 하나로 묶지만,
내부 형식은 다른데요.
System.Tuple<T1, T2> // class
System.ValueTuple<T1, T2> // struct
Tuple은 클래스이고 ValueTuple은 구조체입니다.
그렇기 때문에 Tuple은 참조 형식 ValueTuple은 값 형식으로 Tuple은 일반적으로 힙 메모리에 할당되어
GC 관리 대상이지만 ValueTuple은 스택 메모리여서 GC 걱정이 없습니다. (클래스의 필드가 아니고 배열에 있지 않을때)
또한 Tuple은 ValueTuple처럼
var stats = (mana: 50, health: 100);
(int mana, int health) = stats;
구조를 분해할 수 없는데요.(튜플 문법)
C#의 튜플 문법과 ValueTuple은 구조 분해를 기본적으로 지원하지만, System.Tuple은 같은 방식의 구조 분해를 기본적으로 제공하지 않습니다...
또한 값 변경 가능 여부도 다른데요
Tuple은 요소들은 읽기 전용 프로퍼티이기 때문에
var stats = Tuple.Create(50, 100);
// stats.Item1 = 20; // 불가능
이렇게 바꾸는 것이 불가능합니다.
하지만 Tuple과 다르게 ValueTuple은 요소들이 필드이어서 변경할 수 있습니다.
var stats = (mana: 50, health: 100);
stats.mana = 20; //"가능"
Tuple은 약간 과거에서 사용하는 클래스입니다. 최신으로 넘어오면서 ValueTuple 생기고
Tuple은 거의 사용하지 않게 되었는데요... 그래서 몰라도 크게 상관 없을 것 같긴 합니다....
이상으로 튜플 문법에 관해서 알아보았는데요~!
찾아보고 공부하면서 더 궁금한점이 생기고 다시 찾아보고 하면서 몰랐던 부분까지 알게되어
오늘도 굉장히 알찼습니다. ☺️
내일은 더욱 알차게 보내고 작성해보도록 하겠습니다.
봐주셔서 감사합니다. ☺️