스위프트 : 가드 렛 vs if 렛


132

나는 Swift에서 Optionals에 대해 읽었으며, if letOptional이 값을 가지고 있는지 확인하는 데 사용되는 예제를 보았습니다 .

그러나 Swift 2.0에서는 키워드 guard let가 주로 사용되는 것을 보았습니다 . if letSwift 2.0에서 제거 되었는지 아니면 여전히 사용할 수 있는지 궁금합니다 .

나는 포함 내 프로그램을 변경해야합니다 if let에를 guard let?

답변:


164

if letguard let비슷한 역할을하지만, 서로 다른 목적.

의 "else"케이스 guard는 현재 범위를 종료해야합니다. 일반적으로 이는 return프로그램을 호출 하거나 중단 해야 함을 의미합니다 . guard나머지 함수를 중첩하지 않고도 조기 반환을 제공하는 데 사용됩니다.

if let범위를 중첩하고 특별한 것은 필요하지 않습니다. 할 수 return있거나 할 수 없습니다.

일반적으로 if-let블록이 함수의 나머지 부분이되거나 해당 else절에 a return또는 abort가 있으면 guard대신 사용해야합니다 . 이것은 종종 (적어도 내 경험상) 의심스러운 경우 guard일반적으로 더 나은 대답 임을 의미 합니다. 그러나 if let여전히 적절한 상황이 많이 있습니다.


38
케이스가 유효 if let할 때 사용 non-nil합니다. 케이스가 일종의 오류를 나타낼 guard때 사용 nil합니다.
BallpointBen

4
@BallpointBen 나는 그것에 동의하지 않습니다. guard오류가 없어도 적절한 경우가 많이 있습니다 . 때로는 할 일이 없음을 의미합니다. 예를 들어 positionTitle메서드는 guard if let title = title else {return}. 제목은 선택 사항 일 수 있으며이 경우 오류가 아닙니다. 그러나 guard let여전히 적절합니다.
Rob Napier

1
네; 나는 코멘트에 가드 렛을 의미했다.
Rob Napier

1
즉, "guard let"은 코드가 else 조건을 사용하지 않는다고 99 % 확신 할 때 사용됩니다. 반면에 "if let"은 코드가 50-50 (예) 일 때 else 조건을 사용합니다.
Chino Pan

1
바인딩 된 변수 if let는 범위 에서만 볼 수 있습니다 if let. 바인딩 된 변수 guard let는 나중에 볼 수 있습니다. 따라서 가드를 사용하여 선택적 값도 바인딩하는 것이 좋습니다.
boweidmann

105

가드는 선명도 를 향상시킬 수 있습니다.

가드를 사용 하면 가드가 성공할 가능성 이 훨씬 더 높으며 성공 하지 못하면 범위를 일찍 종료하는 것이 다소 중요합니다 . 배열이 비어 있는지 여부에 따라 파일 / 이미지가 있는지 확인하는 것과 같습니다.

func icon() -> UIImage {
    guard let image = UIImage(named: "Photo") else {
        return UIImage(named: "Default")! //This is your fallback
    }
    return image //-----------------you're always expecting/hoping this to happen
}

if-let으로 위의 코드를 작성하면 읽기 개발자에게 50-50 이상임을 전달합니다. 하지만 가드를 사용하면 코드 에 명확성 을 추가 하고 이것이 95 %의 시간 동안 작동 할 것으로 예상한다는 것을 의미합니다. 실패한 경우 이유를 모르겠습니다. 그럴 가능성은 거의 없지만 ...이 기본 이미지를 대신 사용하거나 잘못된 내용을 설명하는 의미있는 메시지로 단언 할 수 있습니다!

  • guard그들이 부작용을 일으킬 때 s를 피하고 , 가드는 자연스러운 흐름 으로 사용되어야 합니다. else절이 부작용을 일으킬 때 가드를 피하십시오 . 가드 는 코드가 제대로 실행 되는 데 필요한 조건을 설정 하여 조기 종료를 제공합니다.

  • 당신은에서 긍정적 인 지점에서 상당한 계산, 리팩토링을 수행 할 때 ifA와 guard문과의 대체 값을 반환 else

From : Erica Sadun의 Swift Style 책

또한 위의 제안과 깨끗한 코드의 결과 로 실패한 가드 문에 어설 션을 추가하기를 원하거나 필요로 할 가능성 이 더 높으며 가독성이 향상되고 예상했던 것을 다른 개발자에게 분명하게합니다.

guard​ ​let​ image =UIImage(named: selectedImageName) else { // YESSSSSS
     assertionFailure("Missing ​​\(​selectedImageName​)​​ asset") 
     return
} 

guard​ ​let​ image =UIImage(named: selectedImageName) else { // NOOOOOOO
​     ​return 
}

From : Erica Sadun의 Swift Style 책 + 일부 수정

( if-lets에 대한 asserts / 전제 조건을 사용 하지 않습니다. 옳지 않은 것 같습니다)

경비원을 사용하면 운명의 피라미드피하여 선명도를 높일 수 있습니다 . Nitin의 답변을 참조하십시오 .


Guard는 변수를 만듭니다.

아무도 잘 설명하지 못했다고 생각하는 중요한 차이점이 하나 있습니다.

모두 guard letif let 포장을 벗긴 변수 그러나

guard let당신이 작성 하는 새로운 변수 가 존재 외부 else문을.

if let당신이 작성되지 않은 새로운 가변 후 다른 문 만 입력 코드 블록을 경우 옵션이 아닌 무기 호입니다. 새로 생성 된 변수 는 코드 블록 내부 에만 존재합니다 .

guard let:

func someFunc(blog: String?) {

    guard let blogName = blog else {
        print("some ErrorMessage")
        print(blogName) // will create an error Because blogName isn't defined yet
        return
    }
    print(blogName) // You can access it here ie AFTER the guard statement!!

    //And if I decided to do 'another' guard let with the same name ie 'blogName' then I would create an error!
    guard let blogName = blog else { // errorLine: Definition Conflicts with previous value.
        print(" Some errorMessage")
        return
    }
    print(blogName)
}

if-let:

func someFunc(blog: String?) {


    if let blogName1 = blog {
        print(blogName1) // You can only access it inside the code block. Outside code block it doesn't exist!
    }
    if let blogName1 = blog { // No Error at this line! Because blogName only exists inside the code block ie {}
        print(blogName1)
    }
}

if letdo 에 대한 자세한 내용은 다음을 참조하십시오. 선택적 바인딩의 재 선언이 오류를 생성하지 않는 이유


가드는 범위를 종료 해야합니다.

(Rob Napier의 답변에서도 언급 됨) :

func 안에guard 정의 해야 합니다. 주요 목적은 조건이 충족되지 않는 경우 범위를 중단 / 반환 / 종료 하는 것입니다.

var str : String?

guard let blogName1 = str else {
    print("some error")
    return // Error: Return invalid outside of a func
}
print (blogName1)

들어 if let당신은 어떤 FUNC 내부에 그것을 할 필요가 없습니다 :

var str : String?    
if let blogName1 = str {
   print(blogName1) // You don't get any errors!
}

guard vs if

이 질문을 guard letvs if letguardvs 로 보는 것이 더 적절하다는 점은 주목할 가치가 if있습니다.

독립형 if은 언 래핑을 수행하지 않으며 독립형도 수행하지 않습니다 guard. 아래 예를 참조하십시오. 값이이면 일찍 종료되지 않습니다 nil. 선택적 값이 없습니다. 조건이 충족되지 않으면 조기에 종료됩니다.

let array = ["a", "b", "c"]
func subscript(at index: Int) -> String?{
   guard index > 0, index < array.count  else { return nil} // exit early with bad index
   return array[index]
}

46

사용 if-let시기와 사용시기 guard는 종종 스타일의 문제입니다.

당신은 말 func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int과 항목 (의 선택적 배열 var optionalArray: [SomeType]?), 그리고 당신이 중 하나를 반환해야 0배열 인 경우 nil(하지-세트) 또는 count배열에 값이있는 경우 (세트)입니다.

다음을 사용하여 if-let다음 과 같이 구현할 수 있습니다 .

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        if let array = optionalArray {
            return array.count
        }
        return 0
    }

또는 다음과 같이 사용하십시오 guard.

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        guard let array = optionalArray else {
            return 0
        }
        return array.count
    }

예제는 기능적으로 동일합니다.

guard정말로 빛나는 곳 은 데이터 유효성 검사와 같은 작업이 있고 잘못된 경우 함수가 조기에 실패하기를 원할 때입니다.

if-let유효성 검사 완료에 가까워 질 때 일련의 s 를 중첩하는 대신 실패 경로가 모두 이미 반환되었으므로 "성공 경로"와 이제 성공적으로 바인딩 된 옵션은 모두 메서드의 주요 범위에 있습니다.


30

일부 (최적화되지 않은) 코드로 가드 문의 유용성을 설명하려고 노력할 것입니다.

이름, 성, 이메일, 전화 번호 및 비밀번호로 사용자 등록을위한 텍스트 필드의 유효성을 검사하는 UI가 있습니다.

textField에 유효한 텍스트가 포함되지 않은 경우 해당 필드를 firstResponder로 만들어야합니다.

다음은 최적화되지 않은 코드입니다.

//pyramid of doom

func validateFieldsAndContinueRegistration() {
    if let firstNameString = firstName.text where firstNameString.characters.count > 0{
        if let lastNameString = lastName.text where lastNameString.characters.count > 0{
            if let emailString = email.text where emailString.characters.count > 3 && emailString.containsString("@") && emailString.containsString(".") {
                if let passwordString = password.text where passwordString.characters.count > 7{
                    // all text fields have valid text
                    let accountModel = AccountModel()
                    accountModel.firstName = firstNameString
                    accountModel.lastName = lastNameString
                    accountModel.email = emailString
                    accountModel.password = passwordString
                    APIHandler.sharedInstance.registerUser(accountModel)
                } else {
                    password.becomeFirstResponder()
                }
            } else {
                email.becomeFirstResponder()
            }
        } else {
            lastName.becomeFirstResponder()
        }
    } else {
        firstName.becomeFirstResponder()
    }
}

위에서 볼 수 있듯이 모든 문자열 (firstNameString, lastNameString 등)은 if 문의 범위 내에서만 액세스 할 수 있습니다. 그래서이 "파멸의 피라미드"를 생성하고 가독성과 이동의 용이성을 포함하여 많은 문제를 가지고 있습니다 (필드의 순서가 변경되면이 코드의 대부분을 다시 작성해야합니다).

guard 문 (아래 코드)을 사용하면 이러한 문자열이 외부에서 사용 가능 {}하고 모든 필드가 유효한 경우 사용 된다는 것을 알 수 있습니다 .

// guard let no pyramid of doom
func validateFieldsAndContinueRegistration() {

guard let firstNameString = firstName.text where firstNameString.characters.count > 0 else {
            firstName.becomeFirstResponder()
            return
        }
guard let lastNameString = lastName.text where lastNameString.characters.count > 0 else {
            lastName.becomeFirstResponder()
            return
        }
guard let emailString = email.text where 
        emailString.characters.count > 3 &&
        emailString.containsString("@") && 
        emailString.containsString(".") else {
            email.becomeFirstResponder()
            return
        }
guard let passwordString = password.text where passwordString.characters.count > 7 else {
            password.becomeFirstResponder()
            return
        }

// all text fields have valid text
    let accountModel = AccountModel()
    accountModel.firstName = firstNameString
    accountModel.lastName = lastNameString
    accountModel.email = emailString
    accountModel.password = passwordString
    APIHandler.sharedInstance.registerUser(accountModel)
}

필드의 순서가 변경되면 각 코드 줄을 위나 아래로 이동하면됩니다.

이것은 매우 간단한 설명이자 사용 사례입니다. 도움이 되었기를 바랍니다!


14

기본적인 차이점

가드 렛

  1. 범위에서 초기 존재 프로세스
  2. return, Throw 등과 같은 기존 점수가 필요합니다.
  3. 범위 밖에서 액세스 할 수있는 새 변수를 만듭니다.

하자면

  1. 범위 밖으로 액세스 할 수 없습니다.
  2. 진술을 반환 할 필요가 없습니다. 하지만 우리는 쓸 수 있습니다

참고 : 둘 다 Optional 변수의 래핑을 해제하는 데 사용됩니다.



2

가드

  • guard하나 개 이상의 조건이 충족되지 않을 경우 문은 범위의 전송 프로그램 제어 출력에 사용됩니다.

  • guard명령문의 조건 값은 유형 Bool 이거나에 브리지 된 유형이어야합니다 Bool. 조건은 선택적 바인딩 선언 일 수도 있습니다.

가드 문은 다음과 같은 형식을 갖습니다.

guard condition else {
    //Generally return
}

하자면

  • 선택적 바인딩 으로도 인기가 있습니다.
  • 선택적 개체에 액세스하기 위해 if let.
if let roomCount = optionalValue {
    print("roomCount available")
} else {
    print("roomCount is nil")
}

1

나는 밥과 함께 스위프트에게서 이것을 배웠다 ..

일반적인 Else-If

 func checkDrinkingAge() {
      let canDrink = true

     if canDrink {
        print("You may enter")
       // More Code
        // More Code
      // More Code

         } else {
         // More Code
    // More Code
    // More Code
    print("Let me take you to the jail")
          }
     }

Else-If 관련 문제

  1. 중첩 된 괄호
  2. 오류 메시지를 찾기 위해 모든 줄을 읽어야합니다.

가드 문 가드 블록은 조건이 거짓 인 경우에만 실행되며 리턴을 통해 함수를 종료합니다. 조건이 참이면 Swift는 가드 블록을 무시합니다. 조기 종료와 적은 수의 브래킷을 제공합니다. +

func checkDrinkProgram() {
       let iCanDrink = true

           guard iCanDrink else {
        // if iCanDrink == false, run this block
         print("Let's me take you to the jail")
          return
        }

         print("You may drink")
           // You may move on
                  // Come on.
                 // You may leave
                // You don't need to read this.
                 // Only one bracket on the bottom: feeling zen.
       }

Else-If를 사용하여 옵션 래핑 해제

가드 문은 일반적인 조건 블록을 else-if 문으로 대체하는 데 유용 할뿐만 아니라 대괄호 수를 최소화하여 옵션을 풀 때에도 좋습니다. 비교하기 위해 먼저 else-if를 사용하여 여러 옵션을 언 래핑하는 방법을 시작하겠습니다. 먼저, 언 래핑 될 세 가지 옵션을 만들어 보겠습니다.

var publicName: String? = "Bob Lee"
var publicPhoto: String? = "Bob's Face"
var publicAge: Int? = nil

최악의 악몽

func unwrapOneByOne() {
         if let name = publicName {
              if let photo = publicPhoto {
                     if let age = publicAge {
                        print("Bob: \(name), \(photo), \(age)")
                                  } else {
                          print("age is mising")
                           }
                  } else {
                      print("photo is missing")
                         }
                  } else {
                        print("name is missing")
                         }
                  }

위의 코드는 확실히 작동하지만 DRY 원칙을 위반합니다. 끔찍합니다. 분해합시다. +

약간 더 좋음 아래 코드는 위 코드보다 더 읽기 쉽습니다. +

func unwrapBetter() {
         if let name = publicName {
       print("Yes name")
                   } else {
               print("No name")
        return
      }

         if let photo = publicPhoto {
             print("Yes photo")
            } else {
           print("No photo")
       return
             }

        if let age = publicAge {
            print("Yes age")
                      } else {
                print("No age")
            return
                           }
     }

Guard로 풀기 else-if 문은 guard로 바꿀 수 있습니다. +

 func unwrapOneByOneWithGuard() {
             guard let name = publicName else {
                  print("Name missing")
              return
                                        }

              guard let photo = publicPhoto else {
              print("Photo missing")
                return
                                            }

                  guard let age = publicAge else {
                   print("Age missing")
                                     return
                                                 }
                 print(name)
                 print(photo)
                 print(age)
         }

Else-If로 여러 옵션 래핑 해제 지금까지 옵션을 하나씩 해제했습니다. Swift를 사용하면 여러 옵션을 한 번에 풀 수 있습니다. 그중 하나에 nil이 포함되어 있으면 else 블록을 실행합니다.

func unwrap() {
  if let name = publicName, let photo = publicPhoto, let age = publicAge {
    print("Your name is \(name). I see your face right here, \(photo), you are \(age)")
  } else {
    // if any one of those is missing
    print("Something is missing")
  }
}

한 번에 여러 옵션을 풀면 nil을 포함하는 것을 식별 할 수 없습니다.

Guard로 여러 옵션을 풀기 물론, 우리는 else-if보다 가드를 사용해야합니다. +

func unwrapWithGuard() {
  guard let name = publicName, let photo = publicPhoto, let age = publicAge else {
    // if one or two of the variables contain "nil"
    print("Something is missing")
    return
  }

  print("Your name is \(name). I see your, \(photo). You are \(age).")
  // Animation Logic
  // Networking
  // More Code, but still zen
}

돌아가서 코드 서식 / 들여 쓰기를 수정하십시오!
pkamb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.