[swift] 스위프트 : 가드 렛 vs if 렛

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

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

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



답변

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

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

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

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


답변

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

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

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]
}


답변

사용 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 를 중첩하는 대신 실패 경로가 모두 이미 반환되었으므로 “성공 경로”와 이제 성공적으로 바인딩 된 옵션은 모두 메서드의 주요 범위에 있습니다.


답변

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

이름, 성, 이메일, 전화 번호 및 비밀번호로 사용자 등록을위한 텍스트 필드의 유효성을 검사하는 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)
}

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

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


답변

기본적인 차이점

가드 렛

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

하자면

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

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


답변

내가 본 가장 명확한 설명은 Github Swift Style Guide에 있습니다 .

if 깊이 수준을 추가합니다.

if n.isNumber {
    // Use n here
} else {
    return
}

guard 하지 않습니다 :

guard n.isNumber else {
    return
}
// Use n here


답변

가드

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

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

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

guard condition else {
    //Generally return
}

하자면

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