5.3 튜플

튜플(Tuple)은 스위프트에서 제공하는 특별한 성격의 집단 자료형으로서, 파이썬에서도 사용되는 자료형입니다. 튜플은 한 가자 타입의 아이템만 저장할 수 있는 배열과 딕셔너리와는 달리 하나의 튜플에 여러 가지 타입의 아이템을 저장할 수 있지만, 선언되고 나면 상수적 성격을 띠므로 값 추가나 삭제 등 변경이 불가능합니다.

튜플은 대괄호를 사용하는 배열이나 집합과 달리 소괄호를 이용하여 정의합니다

(아이템1, 아이템2, ...)

위 튜플 형식처럼 괄호 안에 추가할 아이템만 나열하면 됩니다

let tupleValue = ("a", "b", 1, 2.5, true)

이렇게 구성된 튜플의 각 아이템은 인덱스 속성을 이용해 참조 가능합니다. 하지만 배열의 인덱스 참조 표기 방식에 차이가 있습니다. 배열에서는 대괄호를 사용하지만 튜플에서는 점(dot)을 사용합니다

tupleValue.0 // "a"
tupleValue.1 // "b"
tupleValue.2 // 1 
tupleValue.3 // 2.5
tupleValue.4 // true

튜플 역시 없는 인덱스를 참조하면 오류가 발생하며, 인덱스가 0부터 시작한다는 점은 배열의 인덱스와 같습니다

튜플은 별도 선언 구문은 없지만 타입 어노테이션을 사용하기 위한 타입을 정의할 수 있습니다. 정의되는 타입 어노테이션의 내용은 튜플의 아이템에 따라 달라집니다

var tpl01: (Int, Int) = (100,200)
var tpl02: (Int, String, Int) = (100, "a", 200)
var tpl03: (Int, (String, String)) = (100, ("t", "v"))
var tpl04: (String) = ("sample string")

이처럼 타입 어노테이션을 사용하여 튜플을 선언할 때는 들어갈 아이템의 개수와 순서에 맞게 각각의 타입을 선언해야 합니다. 마지막 tpl04를 주의해서 보아야 합니다. 문자열 하나만 저장하는 튜플로 선언했지만 실제 저장된 결과를 확인해 보면 튜플이 아닌 문자열 변수로 선언됩니다. 여기서 알 수 있는 점은 하나의 아이템만 있는 튜플은 일반 자료형이 된다는 사실입니다

앞서 정의했던 tupleValue에 타입 어노테이션을 적용해봅시다

let tupleValue: (String, Character, Int, Float, Bool) = ("a", "b", 1, 2.5, true)

만약 tupleValue에 타입 어노테이션을 지정해주지 않으면 어떤 일이 벌어질까요?

두 번째 인덱스의 값인 b는 리터럴 그 자체로 String일 수도, Character일 수도 있습니다.하지만 별도 어노테이션을 작성하지 않으면 타입 추론 원칙에 따라 상위 타입인 String으로 추론됩니다. 네 번째 인덱스 2.5의 경우도 Float, Double 모두 적용 가능하므로 상위 타입인 Double로 추론됩니다. 이러면 튜플에서 원치 않는 타입이 만들어지므로 타입 어노테이션을 지정하는 것이 좋습니다

튜플을 인덱스 속성으로만 접근하면 불편할 수 있습니다. 스위프트에서는 튜플의 아이템을 개별 변수나 상수로 각각 할당받는 바인딩(Binding) 방식의 구문도 제공합니다

let tupleValue: (String, Character, Int, Float, Bool) = ("a", "b", 1, 2.5, true)
let (a,b,c,d,e) = tupleValue

print(a) // a
print(b) // b
print(c+2) // 3
print(d*2) // 5.0
print(e) // true

이처럼 바인딩을 통해 개별 아이템에 대응하는 상수나 변수로 각각 할당받을 수 있습니다.

튜플은 값이 정해지면 추가,수정,삭제가 불가능합니다. 따라서 프로그램이 실행되는 동안 값이 변하지 않아야 하는 상수 성격이거나, 값이 바뀔 가능성을 제거할때 사용하면 좋습니다.

튜플은 배열이나 딕셔너리와 달리 다양한 기능을 하는 메서드가 없습니다. 단지 인덱스 속성이 유일합니다. 튜플의 크기 계산이나 for~in과 같은 loop 기능도 없습니다.

이런 특이한 자료형인 튜플이 사용되기 좋은 곳은 함수나 메서드입니다. 둘 이상의 값을 반환할 때 별도의 자료형 객체를 만들거나 배열 또는 딕셔너리를 만들어야 하는데, 이때 튜플을 이용하면 편리합니다.

func getTupleValue() -> (String, String, Int) {
    return("t", "v", 100)
}

let (a,b,c) = getTupleValue()

print(a) // t
print(b) // v
print(c) // 100

아직 함수를 배우진 않았지만 함수에서 (String, String, Int) 타입의 튜플을 반환하고 있습니다. 하나의 함수를 사용하여 세 개의 데이터를 받을 수 있고 각각 a,b,c로 할당하여 필요한 곳에 사용할 수 있습니다.

만약 함수를 실행하여 튜플을 반환받을 때, 데이터들을 전부 사용할 필요가 없다면 아래와 같이 사용할 수 있습니다.

let (a,b,_) = getTupleValue()

print(a) // t
print(b) // v

튜플 내부 세 번째 아이템을 사용하지 않는다면 "_"을 사용할 수 있습니다. 만약 작성하지 않는다면 바인딩하는 튜플 변수 개수와 아이템 개수가 일치하지 않아 컴파일 에러가 발생하게 됩니다.

정리하면 튜플은 반환할 데이터들을 단순히 괄호로 묶는 것만으로 자료형이 만들어지므로 코드가 매우 단순해진다는 이점이 있습니다. 아이템 수정, 추가, 삭제 불가능의 제약이 있더라도 튜플을 사용하는 이유입니다.

Last updated