How do I tell which guard statement failed?

前端 未结 7 1690
醉梦人生
醉梦人生 2020-12-28 17:58

If I’ve got a bunch of chained guard let statements, how can I diagnose which condition failed, short of breaking apart my guard let into multiple statements?

Given

7条回答
  •  天涯浪人
    2020-12-28 18:57

    Very good question

    I wish I had a good answer for that but I have not.

    Let's begin

    However let's take a look at the problem together. This is a simplified version of your function

    func foo(dictionary:[String:AnyObject]) -> AnyObject? {
        guard let
            a = dictionary["a"] as? String,
            b = dictionary[a] as? String,
            c = dictionary[b] else {
                return nil // I want to know more ☹️ !!
        }
    
        return c
    }
    

    Inside the else we don't know what did go wrong

    First of all inside the else block we do NOT have access to the constants defined in the guard statement. This because the compiler doesn't know which one of the clauses did fail. So it does assume the worst case scenario where the first clause did fail.

    Conclusion: we cannot write a "simple" check inside the else statement to understand what did not work.

    Writing a complex check inside the else

    Of course we could replicate inside the else the logic we put insito the guard statement to find out the clause which did fail but this boilerplate code is very ugly and not easy to maintain.

    Beyond nil: throwing errors

    So yes, we need to split the guard statement. However if we want a more detailed information about what did go wrong our foo function should no longer return a nil value to signal an error, it should throw an error instead.

    So

    enum AppError: ErrorType {
        case MissingValueForKey(String)
    }
    
    func foo(dictionary:[String:AnyObject]) throws -> AnyObject {
        guard let a = dictionary["a"] as? String else { throw AppError.MissingValueForKey("a") }
        guard let b = dictionary[a] as? String else { throw AppError.MissingValueForKey(a) }
        guard let c = dictionary[b] else { throw AppError.MissingValueForKey(b) }
    
        return c
    }
    

    I am curious about what the community thinks about this.

提交回复
热议问题