오늘 학습한 내용중에선 옵셔널 관련 내용을 정리해보자
일단 옵셔널이 무엇이냐?
var optional: Int? = 404
이거다
잘 보면 Int
타입 옆에 ?
가 붙어있는게 보일것이다
저게 옵셔널 변수
를 선언한것이다.
옵셔널 변수는 값이 있을 수도, 없을 수도 있는 변수다.
예제를 통해 살펴봅시다
// 첫번째 예시
var example: Int = 4
print(example)
// 두번째 예시
var example: Int
print(example)
위의 코드를 보자
첫번째 예시는 4
라는 값이 출력될 것이다. 이건 쉽게 예측할 수 있다
그럼 두번째 예시는 어떻게 될까?
아마 에러가 발생할 것이다
왜냐하면 example
이라는 변수에 값이 할당되어 있지 않기때문에 출력할 값이 없기 때문이다.
그럼 이런 상황을 안 만드면 되지 않아? 라고 생각할 수 있지만
실제로 서비스를 제작하다 보면 아직 값이 할당되지 않은 상태로 변수를 만드는 경우가 생긴다.
이런 경우에 쓰는것이 옵셔널
인 것이다.
var example: Int?
print(example)
위의 두번째 예시에 옵셔널 변수만 추가한 것이다.
이제 실행 결과를 보면
에러가 뜨지않고 nil
이 뜨게된다.
참고로 nil
은 다른 언어의 null
이나 NULL
과는 다른 개념이다. nil
은 엄연히 할당된 값으로 여겨진다.
아무튼 이런 옵셔널 변수는 실제로 사용하려면 다른 변수들과 다르게 언래핑
이라는 과정을 거치고 사용해야한다.
이 과정은 택배 상자를 언박싱 하는것에 비유할 수 있다
택배 상자를 개봉했을 때 안에 물건이 있을 수도 있지만 없을수도 있다
그리고 물건이 있다면 사용하기 위해서 상자를 개봉 해야한다.
언래핑 방법에는 크게 옵셔널 바인딩
과 강제 언래핑
이 있다
옵셔널 바인딩은 또 if let
과 guard let
으로 나눌수있다
예제 코드로 확인해 보자
if let
let ticketCounts: Int? = 3 if let ticket = ticketCounts { print (ticket) }
guard let
let x : Int? = 10 // func opbinding() { guard let x = x else { return } print(x) }
둘이 비슷해 보이지만 내가 공부한바로
차이점은 구문내에서 언래핑한 변수를 if let
은 지역 변수로만 사용이 가능하고 guard let
은 전역변수로 사용 가능하다는 점이다.
또, guard
문은 if
문과 다르게 뒤에 항상 else
가 붙어 다니며 else
구문 내에서 return, break, continue 같은 제어구문을 사용한다.
이제 강제 언래핑에 대해서 보자
바로 예시 코드를 보자
let number = Int("42")! print(number) // let address: String? = nil print(address!)
옵셔널 바인딩과 다르게 굉장히 심플하다
언래핑 하고자 하는 값에 !
만 붙여주면 된다.
대신 강제 언래핑은 잘못 사용하면 프로그램에 크래시가 날 수 있기 때문에 nil
값이 확실히 아닌 경우에만 사용해야한다.
그리고 이날 프로그래머스 문제 풀이 중 옵셔널 관련 문제가 나와서 같이 작성해두려고 한다.
https://school.programmers.co.kr/learn/courses/30/lessons/12919
링크를 같이 첨부했다
func solution(_ seoul:[String]) -> String {
var idx = seoul.firstIndex(of: "Kim")!
return "김서방은 \(idx)에 있다"
}
이게 내 첫번째 풀이인데 배열의 인덱싱을 활용해서 풀이했다 firstIndex(of:)
를 쓰면 나오는값이 옵셔널이여서 활용하기위해 강제언래핑으로 언래핑을 진행했다.
근데 내가 아까 위에서 언급했다시피 nil
값이 나올 수도 있는 상황에서는 강제 언래핑을 지양해야한다.
나는 문제 제한 사항에 <"Kim"은 반드시 seoul 안에 포함되어 있습니다.> 라는 문구를 보고 강제 언래핑을 사용했다.
만약 이 문구가 없었고 언래핑을 해야하는 상황이라면 아래 같이
if let
이나 guard let
으로 풀이 했을것이다
if let
func solution(_ seoul: [String]) -> String { guard let idx = seoul.firstIndex(of: "Kim") else { return "" } let result = "김서방은 \(idx)에 있다" return result }
guard let
func solution(_ seoul: [String]) -> String { guard let idx = seoul.firstIndex(of: "Kim") else { return "" } let result = "김서방은 \(idx)에 있다" return result }
이런 식으로 말이다
다른 사람의 강제 언래핑을 활용한 풀이를 봤는데 굉장히 간단하게 잘 풀이해서 첨부해본다
func solution(_ seoul:[String]) -> String {
return "김서방은 \(seoul.firstIndex(of: "Kim")!)에 있다"
프로그래머스 풀이를 보다보면 구문을 되게 간단하게 작성해서
풀이하는 분들이 많은것같다.
내 방법 말고 단순히 배열의 값을을 Kim
과 대조하여 푸는 방법도 봤다.
func solution(_ seoul:[String]) -> String {
for i in 0..<seoul.count {
if seoul[i] == "Kim" {
return "김서방은 \(i)에 있다"
}
}
return ""
}
이 방법인데 둘 다 해당 인덱스를 찾자 마자 위치를 반환하므로 효율성 측면에서는 비슷할것같다.