Reputation: 5144
I have this struct that has an enum property as well as a function:
struct UserInput {
enum State {
case unrestricted
case restricted(because: WarningType)
enum WarningType {
case offline
case forbidden
}
}
var config: UserInputConfig?
var state: State = .unrestricted
func isConfigured() -> Bool {
// Arbitrary checks about the config...
}
}
Is there a way to rewrite the following conditionals so that the check for isConfigured()
and state
are in the same statement?
if case .restricted = userInput.state {
return 1
} else if userInput.isConfigured() {
return 1
} else {
return 0
}
It seems because the State
enum uses associated values, you cannot simply write if userInput.state == .restricted || userInput.isConfigured()
, you need to use the if case
syntax. There must be a way around this?
Upvotes: 1
Views: 315
Reputation: 154691
You would like to do this:
if case .restricted = userInput.state || userInput.isConfigured() {
return 1
} else {
return 0
}
but there is currently no way to do an OR with pattern matching. There are a couple of ways of doing AND.
By using DeMorgan's Laws, you can turn if a || b
into if !(!a && !b)
and by reversing the then and else clauses of your if
statement, you can just check for if !a && !b
.
Unfortunately, you can't say if !(case .restricted = userInput.state)
, but since your enum has only 2 cases, you can replace that with if case .unrestricted = userInput.state
.
Now, how do you use that with another statement? You can't use &&
for the same reason you can't use ||
.
You can check for the failing case by using a pattern that matches both failing conditions (which is using AND) and then return 1
if both failing conditions aren't met:
if case (.unrestricted, false) = (userInput.state, userInput.isConfigured()) {
return 0
} else {
return 1
}
Equivalently you can use a multi-clause condition:
if case .unrestricted = userInput.state, !userInput.isConfigured() {
return 0
} else {
return 1
}
In addition to being shorter and IMO easier to read, this second method can short circuit and skip calling userInput.isConfigured
in the case where case .unrestricted = userInput.state
fails.
Upvotes: 2
Reputation: 1509
You can do it really cleanly with a switch
statement, and pattern matching:
switch userInput.state
{
case .unrestricted:
return userInput.isConfigured() ? 1 : 0;
case .restricted(_):
return 1
}
Upvotes: 1