[Swift] 조건문 (Guard)

Geon·2022년 10월 1일

Swift 기초

목록 보기
10/10
post-thumbnail

Guard는 Swift에서 조건문을 표현하는 또 다른 방식이다. 주로 함수에서 활용이 되며, guard 문은 조건을 만족하지 않을 때 실행된다는 특징이 있다. guard문 사용 시 else를 필수적으로 사용해 주어야 하고, else 문 내부에는 반드시 guard문이 사용되고 있는 반복문이나 함수 등을 탈출시키는 return, throw, break 등의 제어문을 명시해 주어야 한다. 기본적인 구조는 아래와 같다.

guard 조건 else{
	//조건을 만족하지 않을 때 실행할 명령
}
//조건을 만족할 때 실행할 명령

조건을 만족하지 못하면 else 블록의 코드가 실행되며, 만일 조건을 만족한다면 else 블록 밖에 위치한 코드가 실행된다. 아래의 예시를 통해 이해해보자.


func checkNum(num : Int) -> Bool{
	guard num == 1 else{
    	print("번호가 틀렸습니다.")
    	return false //탈출 제어문 필수!
    	}
    return true
}

checkNum(num : 3)

결과 : "번호가 틀렸습니다." //출력 이후 false를 반환하면서 함수 종료

정수형 매개변수를 받고, 그 매개변수가 1인지를 검사하는 checkNum이라는 함수를 만들어 보았다. 함수의 매개변수에 3을 주었기에 매개변수가 1인지 판별하는 guard 조건을 만족하지 않아 "번호가 틀렸습니다"를 출력하고, false를 반환하면서 함수가 종료된다.

여기서 우리가 기억할 점은 else 블록 내부에는 return 등의 탈출을 위한 제어문을 반드시 사용해야 하며, 그로 인해 else 블록 실행 후 함수가 즉시 종료된다는 점이다. 이러한 점에서 Swift 공식 문서에서는 guard문을 'Early Exit'의 성질을 가진다고 표현한다.


Guard-let

guard 문은 '옵셔널 바인딩'에도 많이 쓰인다. Optional에 대한 내용은 후에 자세하게 배우겠지만, 간단히 말하면 값이 존재하거나, 존재하지 않거나(nil : 다른 언어에서 null과 비슷한 느낌이다.)의 상태를 말한다. 옵셔널 바인딩(Optional Binding)은 값이 존재하는지 존재하지 않는지 알 수 없는 Optional 상태에 있는 변수나 상수의 정체를 바인딩을 통해 밝히는 것으로, 만약 값을 가지고 있는 변수나 상수였다면 바인딩에 성공, nil(값이 없음)이었다면 바인딩에 실패하게 된다.

guard optionalBinding else {
	//옵셔널 바인딩에 실패했을 경우에 실행할 명령
}
//옵셔널 바인딩에 성공했을 경우에 실행할 명령

구조는 위와 같으며 아래의 예시 코드를 통해 감을 잡아보자.


func checkName(name: String?) -> Void{
guard let checkedName = name else {
    print("이름이 없습니다.")
    return
    }
    print("이름이 있습니다. 이름은 \(checkedName)")
}

checkName("dryrain") 
결과 : 이름이 있습니다. 이름은 dryrain

checkName(nil)
결과 : 이름이 없습니다.

익숙하지 않은 부분이 보인다. 함수에서 매개변수의 타입을 적는 부분에 물음표가 적혀 있고, guard 뒤에는 checkedName이라는 상수가 선언된다. 한줄씩 설명하면 아래와 같다.


func checkName(name: String?) -> Void{

Void형을 반환하는 checkName 함수이다. 매개변수의 데이터 타입을 명시하는 부분에 String? 이라고 적혀있는데, Optional 상태의 String을 매개변수로 받겠다는 것이다. 즉 매개변수 name 에는 실제 String 형의 값을 가지는 데이터가 오거나, 값이 없는 nil 데이터가 들어갈 수 있다.


guard let checkedName = name else{

옵셔널 바인딩이 이루어지는 부분이다. checkedName에 Optional한 상태의 name이 바인딩 되면서, 만약 name이 실제 String 값을 가지고 있다면 바인딩에 성공하여 아래의 코드가 실행되고,

print("이름이 있습니다. 이름은 \(checkedName)")

name이 nil이라면 바인딩에 실패하여 else 블록 내부에 있는 아래의 코드가 실행된다.

print("이름이 없습니다.")
    return




아래와 같이 guard문을 여러개 사용한 코드도 만들 수 있다.

func checkName(name: String?) -> Void{
guard let checkedName = name else {
    print("이름이 없습니다.")
    return
    }
    print("이름이 있습니다. 이름은 \(checkedName)")
    guard checkedName.count >= 5 else {
        print("이름이 5글자보다 작습니다.")
        return
    }
    
    print("이름이 5글자보다 큽니다.")
}

checkName(name: "dryrain")
결과 : 이름이 있습니다. 이름은 dryrain
이름이 5글자보다 큽니다.

checkName(name: "kim")
결과 : 이름이 있습니다. 이름은 kim
이름이 5글자보다 작습니다.

checkName(name: nil)
결과 : 이름이 없습니다.

우선 첫번째 guard문에서 옵셔널 바인딩을 통해 값이 있는지 없는지를 판별하고 값이 없다면 "이름이 없습니다" 출력 후 함수를 종료, 만일 값이 있다면 else의 바깥쪽 코드인

print("이름이 있습니다. 이름은 \(checkedName)")
    guard checkedName.count >= 5 else {
        print("이름이 5글자보다 작습니다.")
        return
    }
    
    print("이름이 5글자보다 큽니다.")
}

가 실행되며, .count를 통해 checkedName 상수가 가지고 있는 문자열의 글자 수를 센 후 다섯 글자 미만이면 "이름이 5글자보다 작습니다"를 출력하고 함수를 종료, 다섯 글자 이상이면 else 바깥에 있는 print("이름이 5글자보다 큽니다.")가 실행된다.

처음 보면 복잡하게 느껴질 수 있지만 조건을 만족하지 않으면 else로, 조건을 만족하면 else 블록을 통과하는 흐름만 숙지한다면 어렵지 않을 것이다.

profile
별에 별 지식 저장해놓고 꺼내먹기📚

0개의 댓글