[swift 기초] 데이터 타입(2)

silverCastle·2021년 8월 11일
0
post-thumbnail

💡데이터 타입 고급

swift가 컴파일 시 타입을 확인하는 것을 타입 확인이라고 하는데 이를 통해 여러 타입을 섞어 사용할 때 발생할 수 있는 런타임 오류를 피할 수 있다.

✍️ 타입 별칭

기본적으로 제공하는 데이터 타입이든, 사용자가 임의로 만든 데이터 타입이든 이미 존재하는 데이터 타입에 임의로 다른 이름(별칭)을 부여할 수 있다.

typealias MyInt = Int
typealias YourInt = Int
var num1: MyInt = 10
var num2: YourInt = 20
var num3: Int = 30
num1 = num2
num2 = num3
num3 = num1

✍️ 튜플

타입의 이름이 따로 없으며, 프로그래머 마음대로 만드는 타입이다. '지정된 데이터의 묶음'이라고 표현할 수도 있다.
튜플의 각 요소를 접근하려면 각 요소를 이름이 아니라 숫자로 표현하기 때문에 차후에 프로그래머가 코드를 볼 때 불편함이 있을 수 있으므로 튜플의 각 요소마다 이름을 붙여줄 수도 있다.

var person: (name: String, age: Int, height: Double) = ("silverCastle",24,174.5)
print("name: \(person.name)")
print("age: \(person.age)")
print("height: \(person.height)")

결과

name: silverCastle
age: 24
height: 174.5

타입 별칭을 이용해 튜플을 만들 수도 있다.

typealias PersonData = (name: String, age: Int, height: Double)
var person1: PersonData = ("silverCastle",24,174.5)
var person2: PersonData = ("goldCastle",20,170)
print(person1)
print(person2)

결과

(name: "silverCastle", age: 24, height: 174.5)
(name: "goldCastle", age: 20, height: 170.0)

✍️ 컬렉션형

튜플 외에도 많은 수의 데이터를 묶어서 저장하고 관리할 수 있는 컬렉션 타입이 있다. 프로그래머가 이를 잘 숙지한다면 더 효율적으로 프로그래밍할 수 있을 것이다.

🔎 배열

같은 타입의 데이터를 일렬로 나열한 후 순서대로 저장하는 형태의 컬렉션 타입이다. 서로 다른 위치에 같은 값이 들어갈 수 있음을 기억하자.
또한 C언어와는 다르게 필요에 따라 자동으로 크기를 조절해주므로 요소의 삽입 및 삭제가 자유롭다.

//var names: Array<String> = ["bronzeCastle","silverCastle","goldCastle"]	// 아래와 동일한 표현이다.
var names: [String] = ["bronzeCastle","silverCastle","goldCastle"]
print(names)
names.append("diamondCastle")
print(names)
names.insert("platinumCastle", at: 3)
print(names)
names.insert(contentsOf: ["start","end"], at: 5)
print(names)
names.remove(at: 5)
print(names)
names.removeLast()
print(names)

결과

["bronzeCastle", "silverCastle", "goldCastle"]
["bronzeCastle", "silverCastle", "goldCastle", "diamondCastle"]
["bronzeCastle", "silverCastle", "goldCastle", "platinumCastle", "diamondCastle"]
["bronzeCastle", "silverCastle", "goldCastle", "platinumCastle", "diamondCastle", "start", "end"]
["bronzeCastle", "silverCastle", "goldCastle", "platinumCastle", "diamondCastle", "end"]
["bronzeCastle", "silverCastle", "goldCastle", "platinumCastle", "diamondCastle"]

만약, 접근하려는 인덱스가 인덱서의 범위를 벗어난다면 어떻게 될까?
당연하듯이, 오류를 내뱉게 된다.

print(names[10])

결과

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

🔎 딕셔너리

요소들이 순서와 상관없이 항상 키와 값의 쌍으로 구성되는 컬렉션 타입이다. 하나의 딕셔너리 안에는 같은 키가 중복될 수 없음을 기억하자.

var numberForName: [String: Int] = ["bronzeCastle": 21, "silverCastle": 24, "goldCastle": 25]
print(numberForName)
print(numberForName.count)
print(numberForName["silverCastle"]!)
print(numberForName.removeValue(forKey: "bronzeCastle")!)
print(numberForName["diamondCastle", default: 0])
numberForName["diamondCastle"] = 100
print(numberForName["diamondCastle"]!)

결과

["goldCastle": 25, "bronzeCastle": 21, "silverCastle": 24]
3
24
21
0
100

여기서 출력할 때 !가 붙는 이유는 값이 있을 수도 있고 없을 수도 있기 때문에 옵셔널(Optional)로 정의되어 있는데 키워드인 !를 붙이면 이 옵셔널에 값이 있다고 가정하고 값에 바로 접근할 수 있도록 도와주기 위한 것이다.
만약 키워드 !가 없다면 아래와 같은 오류를 내뱉게 된다.

Expression implicitly coerced from 'Int?' to 'Any'

🔎 세트

같은 타입의 데이터를 순서와 상관없이 하나의 묶음으로 저장하는 형태의 컬렉션 타입이다. 세트 내의 값은 모두 유일한 값으로 중복될 수 없음을 기억하자.
그래서 세트는 보통 순서가 중요하지 않거나 각 요소가 유일한 값이어야 하는 경우에 사용한다.
배열과 달리 축약형(ex. Array[Int]를 [Int]로 축약)이 없다.

// 순서가 없기 때문에 매 출력마다 값이 다르게 나올 수 있다.
var names: Set<String> = ["bronzeCastle","silverCastle","goldCastle","silverCastle"]
print(names)
names.insert("diamondCastle")
print(names)

결과

["bronzeCastle", "silverCastle", "goldCastle"]
["bronzeCastle", "diamondCastle", "silverCastle", "goldCastle"]

✍️ 열거형

연관된 항목들을 묶어서 표현할 수 있는 타입이다. 다음과 같은 경우에 요긴하게 사용할 수 있다.

  • 제한된 선택지를 주고 싶을 때
  • 정해진 값 외에는 입력받고 싶지 않을 때
  • 예상된 입력 값이 한정되어 있을 때

🔎 기본 열거형

열거형은 enum 키워드를 통해 선언할 수 있다.

enum School {
    case primary, elementary, middle, high, college, university, graduate
}
let highSchoolStudent: School = School.high

🔎 원시 값

열거형의 각 항목은 자체로도 하나의 값이지만 항목의 원시값(Raw Value)도 가질 수 있다. 특정 타입의 값을 원시 값으로 가지고 싶다면 열거형 이름 오른쪽에 타입을 명시해주면 된다.

enum School: String {
    case primary = "유치원"
    case elementary = "초등학교"
    case middle = "중학교"
    case high = "고등학교"
    case college = "대학"
    case university = "대학교"
    case graduate = "대학원"
}
let highSchoolStudent: School = School.high
// 원시 값을 사용하고 싶다면 rawValue 프로퍼티를 이용하자.
print("저는 \(highSchoolStudent.rawValue) 학생입니다.")

결과

저는 고등학교 학생입니다.

🔎 연관 값

각 항목 옆에 소괄호로 묶어 표현할 수 있다.

enum MainDish {
    case pasta(taste: String)
    case pizza(dough: String, topping: String)
    case chicken(withSauce: Bool)
    case rice
}
var dinner: MainDish = MainDish.pasta(taste: "크림")
print(dinner)
dinner = .pizza(dough: "치즈크러스트", topping: "불고기")
print(dinner)
dinner = .chicken(withSauce: true)
print(dinner)
dinner = .rice
print(dinner)

결과

pasta(taste: "크림")
pizza(dough: "치즈크러스트", topping: "불고기")
chicken(withSauce: true)
rice

🔎 항목 순회

열거형에 포함된 모든 케이스를 알고 싶을 때 사용한다. 열거형의 이름 뒤에 콜론(:)을 작성하고 한칸 띄운 뒤 CaseIterable 프로토콜을 적으면 된다.

enum School: CaseIterable {
    case primary, elementary, middle, high, college, university, graduate
}
// 모든 케이스의 컬렉션을 생성하려면 allCases 프로퍼티를 이용하자.
let allCases: [School] = School.allCases
print(allCases)

결과

[__lldb_expr_56.School.primary, __lldb_expr_56.School.elementary, __lldb_expr_56.School.middle, __lldb_expr_56.School.high, __lldb_expr_56.School.college, __lldb_expr_56.School.university, __lldb_expr_56.School.graduate]

🔎 순환 열거형

열거형 항목의 연관 값이 열거형 자신의 값이고자 할 때 사용한다. indirect 키워드를 사용하면 되는데 특정 항목에만 적용하고 싶다면 case 키워드 앞에 indirect를 붙이면 되고, 열거형 전체에 적용하고 싶다면 enum 키워드 앞에 indirect를 붙이면 된다.

enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

🔎 비교 가능한 열거형

열거형의 각 케이스를 비교하고 싶을 때 사용한다. 열거형의 이름 뒤에 콜론(:)을 작성하고 한칸 띄운 뒤 Comparable 프로토콜을 적으면 된다.
참고로, 앞에 위치한 케이스가 더 작은 값을 가진다.

enum Condition: Comparable {
    case bad
    case good
    case great
}
let myCondition: Condition = Condition.great
let yourCondition: Condition = Condition.bad
if myCondition >= yourCondition {
    print("제 상태가 더 좋군요.")
}
else {
    print("당신의 상태가 더 좋군요.")
}

결과

제 상태가 더 좋군요.

0개의 댓글