var yourName : String
print(yourName) // 선언만 하고, 값을 초기화하지 않았는데 접근하려고 하면 에러가 발생한다
이럴 때 앱이 종료되지 않도록 옵셔널(Optional)이라는 개념을 도입한다
var yourName : String? // 변수에 '임시값(nill)'을 넣는다.
어떤 타입에 물음표(?)를 붙인 걸 옵셔널 타입이라고 한다.
Int : 정수형
Int? : 옵셔널 정수형
: ...-3, -2, -1, 0, 1, 2, 3, ... + nill
Int와 Int?는 다른 type이다.
Optional 타입과 Non-optional 타입은 서로 다른 타입이다
nill : 실제 값이 없는 게 아니고, "값이 없음을 표현하는 키워드이다.
단점
포장지(임시적인 타입)로 싸고 있는 느낌이기 때문에
실제 값을 사용하려면, 포장지를 한 번 벗겨주어야 한다.
이 때, nill일 때 벗겨서 사용하려고 하면 그 안에는 값이 없기 때문에 에러가 난다
var num : Int? = 3
var yourAge : Int? = nill // nill로도 초기화할 수 있다
num = nill
var yourAge = nill (X) // 무슨 옵셔널 타입인지 추론할 수가 없다
정식문법
let num1 : Int? = 2 // 간편한 방법
let num2 : Optional(Int> = 0 // 정식 문법
주의
let optionalStr : String? = nill // 잘못된 구문
// nill로 선언하면, 값이 변할 가능성을 주어야 하는데, let을 이용해서 상수로 선언하면 아무 의미가 없어진다
// optional type nill은 항상 변수로 사용한다
var optionalStr : String? = nill
값 복사
var a : Int? = 2
var b = a
// b의 타입은 Optional<Int>
// print(b) : Optinoal(2)
var c = Int = 5
var b = c
// 이렇게 하면 b에 c의 값을 담을 수는 있지만, 타입이 바뀌게 된다.
// print(b) : Optional(5)
연산 불가능
var num1 : Int? = 3
var num2 : Int? = 7
//print(num1 + num2) -> 에러.
포함관계
4가지 방법 + 옵셔널 체이닝(Chaining)
var num : Int?
var str : String? = "Hi"
// print(num) : nill
// print(str) : Optional("Hi")
print(str!) : "Hi"
print(num!) -> 에러
if str != nill {
print(str!)
}
if num != nill {
print(num)
}
if let s = str {
print(s)
}
var optionalName : String? = "홍길동"
if let name = optionalName {
print(name)
}
func doSomething(name : String) {
guard let name = optionalName else { return }
print(name)
}
(=)
func doSomething(name : String?) { // 옵셔널 타입을 input으로 받을 수도 있다
guard let n = name else { return } // * guard문 안에서 선언한 변수는 그 밖에서도 사용 가능하다!! 동일한 scope로 취급한다
print(n)
}
var serverName : String? = "홍길동" // Optional("홍길동")
var userName = serverName ?? "미인증사용자" // 기본값(디폴트값)을 지정해준다
// 값이 있으면 그 값을 사용하고, nill이 들어있다면 "미인증사용자"를 사용하겠다
// -> nill이 나올 수가 없다!!
var hello = "인사하겠습니다. " + (str ?? "Say, Hi")
// 인사하겠습니다 "Hi"
삼항연산자를 이용한 풀이
var userName = (serverName != nill) ? serverName : "미인증사용자"
func doSomePrint(with label : String, name : Strint? = nill) { // 기본값으로 nill을 설정해둔다
print("\(label) : \(name)")
}
doSomePrint(with : "레이블", name : "스티브 잡스")
doSomePrint(with : "레이블") //nill로 기본값을 설정해두었기 때문에 쓰기가 편하다.