Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
362 views
in Technique[技术] by (71.8m points)

enums - Swift switch statement considered all cases of Int, but compiler still display error

I understand switch statement in Swift must be exhaustive, otherwise we have to provide an default case. I saw the code below online, the switch statement already have covered all cases in Int, but the compiler still display error message that switch must be exhaustive, consider adding a default clause. Is there something I'm missing?

extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }

    var kind: Kind {
        switch self {
        case 0:
            return .Zero
        case let x where x > 0:
            return .Positive
        case let x where x < 0:
            return .Negative
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Update for Swift 3: Swift 3 introduced ClosedRange which makes it possible to define a range like 1...Int.max including the largest possible integer (compare Ranges in Swift 3). So this compiles and works as expected, but still requires a default case to satisfy the compiler:

extension Int {
    enum Kind {
        case negative, zero, positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .zero
        case 1...Int.max:
            return .positive
        case Int.min...(-1):
            return .negative
        default:
            fatalError("Oops, this should not happen")
        }
    }
}

There are other bug reports where the Swift compiler does not correctly determine the exhaustiveness of switch-statements, such as https://bugs.swift.org/browse/SR-766, where Apple engineer Joe Groff commented:

Unfortunately, integer operations like '...' and '<' are just plain functions to Swift, so it'd be difficult to do this kind of analysis. Even with special case understanding of integer intervals, I think there are still cases in the full generality of pattern matching for which exhaustiveness matching would be undecidable. We may eventually be able to handle some cases, but there will always be special cases involved in doing so.


Old answer: The compiler is not so smart to recognize that you have covered all possible cases. One possible solution is to add a default case with a fatalError():

var kind: Kind {
    switch self {
    case 0:
        return .Zero
    case let x where x > 0:
        return .Positive
    case let x where x < 0:
        return .Negative
    default:
        fatalError("Oops, this should not happen")
    }
}

Or make case 0: the default case:

var kind: Kind {
    switch self {
    case let x where x > 0:
        return .Positive
    case let x where x < 0:
        return .Negative
    default:
        return .Zero
    }
}

(Remark: I initially thought that the following would work correctly without needed a default case:

var kind: Kind {
    switch self {
    case 0:
        return .Zero
    case 1 ... Int.max:
        return .Positive
    case Int.min ... -1:
        return .Negative
    }
}

However, this compiles, but aborts at runtime because you cannot create the range 1 ... Int.max. More information around this problem can be found in the article Ranges and Intervals in Swift.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...