Why can't I use a tuple constant as a case in a switch statement
You could implement the ~=
operator for the mydTuple
type like this:
func ~=(a: mdyTuple, b: mdyTuple) -> Bool {
return a.month ~= b.month && a.year ~= b.year && a.day ~= b.day
}
That worked for me in a Playground... Now, this code
switch someday {
case joesBirthday:
println("one")
default:
println("two")
}
prints "one".
This is the operator's definition:
infix operator ~= {
associativity none
precedence 130
}
and is implemented for the following:
/// Returns `true` iff `pattern` contains `value`
func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
func ~=<T>(lhs: _OptionalNilComparisonType, rhs: T?) -> Bool
func ~=<T : Equatable>(a: T, b: T) -> Bool
func ~=<I : ForwardIndexType where I : Comparable>(pattern: Range<I>, value: I) -> Bool
Swift switch statement on a tuple of optional booleans
There are a bunch of ways to do this, but to fix the syntax of what you are trying to do literally, you need to explicitly unbox the Optional, either by matching against .Some(false), or unwrapping it with ! (which I think is kind of weird, as you'll see)
var dict = Dictionary<String,Bool>()
dict["a"] = true
dict["c"] = false
func matchOneOrTheOtherWithOptionals(a: Bool?, b: Bool?) -> String {
switch (a, b) {
case (.Some(true), let b) where b == .None || !b!: // gross
return "a was true, but b was None or false"
case (let a, .Some(true)) where a == .None || a == .Some(false):
return "a was None or false and b was true"
default:
return "They both had a value, or they were both missing a value"
}
}
matchOneOrTheOtherWithOptionals(true, .None) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(true, false) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(.None, true) // "a was None or false and b was true"
matchOneOrTheOtherWithOptionals(false, true) // "a was None or false and b was true"
matchOneOrTheOtherWithOptionals(false, false) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(true, true) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(.None, .None) // "They both had a value, or they were both missing a value"
You could also try the following:
func noneToFalse(bool: Bool?) -> Bool {
if let b = bool {
return b
} else {
return false
}
}
func matchOneOrTheOther(a: Bool, b: Bool) -> String {
switch (a, b) {
case (true, false):
return "a is true, b was false or None"
case (false, true):
return "a was false/None, b was true"
default:
return "both were true, or both were false/None"
}
}
matchOneOrTheOther(noneToFalse(dict["a"]), noneToFalse(dict["b"]))
Here's a gist of the Playground I used while writing this answer: https://gist.github.com/bgrace/b8928792760159ca58a1
Swift tuple switch case : pattern of type cannot match values of type
Solution 1
let ABOUTTROVPROTECTIONCELL = (section: 1, row: 0)
let cellIdentifier = (section: indexPath.section, row: indexPath.row)
switch cellIdentifier {
case (ABOUTTROVPROTECTIONCELL.section, ABOUTTROVPROTECTIONCELL.row):
print("here")
default:
print("bleh")
}
Solution 2
Just use IndexPath
struct and its initializer for creating ABOUTTROVPROTECTIONCELL
let ABOUTTROVPROTECTIONCELL = IndexPath(row: 0, section: 1)
let cellIdentifier = indexPath // Not necessary, you can just use indexPath instead
switch cellIdentifier {
case ABOUTTROVPROTECTIONCELL:
print("here")
default:
print("bleh")
}
Solution 3
Implement ~=
func for your tuple:
typealias IndexPathTuple = (section: Int, row: Int)
func ~=(a: IndexPathTuple, b: IndexPathTuple) -> Bool {
return a.section ~= b.section && a.row ~= b.row
}
let ABOUTTROVPROTECTIONCELL = (section: 1, row: 0)
let cellIdentifier = (section: indexPath.section, row: indexPath.row)
switch cellIdentifier {
case ABOUTTROVPROTECTIONCELL:
print("here")
default:
print("bleh")
}
case (let name, let x)
A tuple is just a variable that carries more than one value. In your example the tuple is of the type (String, Int)
because that's how you first defined it.
Like when you do let name = "Matt"
this is just doing that except with an Int
alongside the string.
The switch is then then checking that tuple based on the pattern matching.
The (let name, let x)
is just taking the values from that tuple and inserting them into the variables named name
and x
so that they can be used. Without this you would not be able to print the name or age in the code.
If you didn't care about the name you could do...
case (_, let x):
print("This person is \(x) years old")
You can't print the name here because you haven't put it into a variable name.
You could also do case (let dog, let z):
. This would work and now the variable dog
would be a String
with the value "Matt". Except it doesn't really make sense to do this because the value is a name be not a dog. :-)
If you had made your first line as...
let tuple = ("Oliver", 33)
Then the name variable would be "Oliver" and the X would be 33.
Syntax for expanding a tuple used in an enum when using a switch statement
In addition to your Update: answer:
case .FirstCase(output: let (someString, someInt)):
and
case let .FirstCase(output: (someString, someInt)): // thanks @MartinR
work as well.
By having the output:
label in your enum
case, you have created a named tuple of one value containing a named tuple of two values. If you don't specify output:
in the switch
, Swift is going to attempt to match the outer tuple with the tuple you supply and the count of the items doesn't match.
Providing the output:
label in the pattern allows Swift to know that you are talking about the inner tuple, and it then works.
If you feel output:
is pointless, why include it in your enum definition at all?
Why is 'case' inside a switch statement negative indented?
Well, I would guess that the break
statement belongs to the "section" in the case clause. And as any other statement, it is indented relative to the case
. As for the case
relative to switch
- well I don't know.
But I'm completely with you - and formatting is a matter of personal preference anyway. Since the formatting rules in Xcode are not explicitly defined - it cannot be a bug ;)
FWIW, I prefere this style
switch x {
case 1:
// do something
break
case 2:
// do something else
break
default:
// default
break
}
Getting Binary operator ~= cannot be applied to two (Int, Int) operands in Swift switch statement with (Int, Int) tuple cases
Do this.
switch (indexPath.section, indexPath.row) {
case (IndexPath.Gender.tuple.0, IndexPath.Gender.tuple.1):
// Do something.
case (IndexPath.Weight.tuple.0, IndexPath.Weight.tuple.1):
// Do something.
case (IndexPath.EmergencyContact.tuple.0, IndexPath.EmergencyContact.tuple.1):
// Do something.
default:
break;
}
What does constant binding in switch statements actually do?
From your quote from the Swift documentation:
... can then be referenced in a corresponding where clause and throughout
the rest of the code within the scope of the case.
So in the first case
case let (x,y) where x == y:
print("hello")
greeting
(which is the tuple (1, 10)
) is matched against the
pattern
let (x,y) where x == y
and if it matches, x
is bound to the first tuple element
and y
to the second.
This binding is restricted to the scope of the first case,
and cannot be used in the second or other cases.
To make your code compile, add another let
binding for the second
case:
switch greeting {
case let (x,y) where x == y:
print("\(x) is equal to \(y)")
case let (x,y) where x < y:
print("\(x) is less than \(y)")
default:
print("No match")
}
Related Topics
Swiftier Swift for 'Add to Array, or Create If Not There...'
Get Current Time as String Swift 3.0
Accessing Mkmapview Elements as Uiviewrepresentable in the Main (Contentview) Swiftui View
Swiftui Exporting or Sharing Files
How to Get the Height of a Uilabel in Swift
Anonymous Closure Argument Not Contained in a Closure
How to Filter Characters from a String in Swift 4
Multiplying Variables and Doubles in Swift
How to Have a Swift Script Use Multiple Files
How to Execute Code Once and Only Once in Swift
Only First Track Playing of Avmutablecomposition()
Cannot Invoke 'Join' with an Argument List of Type (String, [String]) in Swift 2.0
What Determines Whether a Swift 5.5 Task Initializer Runs on the Main Thread
Swift Map(_:) Extension for Set()
Using Non Ns_Enum Objective-C Enum in Swift
Listing All Files in a Folder Recursively with Swift
Swiftui: How to Implement a Custom Init With @Binding Variables