Reputation: 17585
I couldn't understand exact meaning of this statement.
let x where x.hasSuffix("pepper")
What is meaning of that?
Note: There is no need of let
use? It makes me confusing.. Is this enough x where x.hasSuffix("pepper")
? because, let x
should be already get assigned.?
Update: From @Jacky comment here, it could be meaning same as below.
let x = vegetable
if (x.hasSuffix("pepper")
......
Upvotes: 15
Views: 5061
Reputation: 28572
Let
is not useful in this example, and can be removed:I modified the code OP was referring (available in the GuidedTour to exclude let x
, to show that let x
is completely useless. Readability is also improved, as x
is no longer present. This is at the heart of OP's (Mani) question: why use let
? The answer is, in this case, you shouldn't.
Using x
is confusing, what does it mean? And finally, why would you need to redeclare a constant (vegetable
as x
), because it is not going to change. It pointless!
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case vegetable where vegetable.hasSuffix("pepper"):
print("Is it a spicy \(vegetable)?")
default:
print("Everything tastes good in soup.")
}
// Prints "Is it a spicy red pepper?"
First of all, the where
keyword allows you to execute arbitrary code inside each case, so that you can run different code in different case condition. Without this, a switch statement will just check for equality between the argument and the case.
Limited: each case condition compares the switch statement condition (age
) to the case expression, because where
is not used:
switch age {
case 20:
print("He is 20")
case 21:
print("He is 21")
print("or... he is \(age)")
default:
print("He is in an unknown age group.")
}
Better: We can now execute code in the case expression, because where is used (Notice no let is used). This allows ranges, and more complex expressions to be used, which will shorten the size of the switch statement:
switch age {
case let age where age < 20:
print("He is younger than 20")
case age where 20 < age && age < 30:
print("He is between 20 and 30")
print("\(age)")
default:
print("He is in an unknown age group.")
}
No benefit gained: There is no use creating a new constant to hold the exact value as the argument to switch:
switch age {
case let age where age < 20:
print("He is younger than 20")
case let age_2 where 20 < age_2 && age_2 < 30:
print("He is between 20 and 30")
print("\(age == age_2) is True, and will always be True. Useless!")
default:
print("He is in an unknown age group.")
}
So, redeclaring the switch condition (age
or vegetable
) using let x ...
is completely useless.
let vegetable
can come in useful here, when we don't have a variable or constant for the value passed into switch:
func getVegetable() -> String {
return "Sweet Potato"
}
switch(getVegetable()) {
case "Pepper":
print("Spicy!")
case let vegetable where vegetable.hasSuffix("Potato"):
print("eww potatoes!")
default:
print("Unknown vegetable")
}
It is more useful when you want to unpack the argument passed to the switch statement:
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"
source (read value binding section). It actually allows you to match the rest of the switch argument, and declare a more useful variable.
I would've called this feature variable unpacking or switch unpacking or switch unpacking or aliasing or partial matching instead of value binding. When you declare any variable, you are binding a value to that variable too... "value binding" is a meaningless/ broad name.
Upvotes: 1
Reputation: 1143
"where" clause introduced in swift 2 but never got a recognition from developers for its usage. It is used for pattern matching and can be used with for-in, switch statements. It is basically a part of control flow and can be used anywhere in your code. Some examples are as follows
//Example usage in switch
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
//Example usage in for
let arr = [1,2,3,4]
for value in arr where value != 0 {
print(value)
}
Upvotes: 0
Reputation: 1060
case let x where x.hasSuffix("pepper")
The simple explanation is that you cannot match a case, that is of type String
, with .hasSuffix()
because it returns a Bool
. So, they give you this where
pattern matching keyword to use. It works like this:
let x
copies the String value you are passing into the switch to the constant x. where
is a boolean evaluation that will only let the case complete the match if it is given a true bool, just like an if
block.hasSuffix()
returns the bool required by where
.If your string variable passed into the switch is var foo
. You can literally do this instead:
case foo where foo.hasSuffix("pepper")
You can pass a true bool to where like this and it would work, uselessly:
case foo where true
Upvotes: 7
Reputation: 5316
This is a larger view of the code:
switch vegetable {
... omissis ...
case let x where x.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
default:
let vegetableComment = "Everything tastes good in soup."
}
What it does is match the value of vegetable
assigning it to x
and testing if it has suffix "pepper"
. If the match succeeds it executes the case block let vegetableComment = "Is it a spicy \(x)?"
otherwise it continues with the next test (which in this case is a default:
).
Note that the let
is necessary. It means that you are binding a new variable x
.
Also note that it's not the same as
case let x:
if (x.hasSuffix("pepper")
...
as this always succeeds and enters the case block, while using the where
clause means that if the condition is not satisfied the match fails and the next case
(or default
) shall be tried.
Upvotes: 4
Reputation: 25917
The where
in that context is used as pattern matching. From the example:
case let x where x.hasSuffix("pepper"):
When the suffix of x
matches "pepper"
it will set the constant vegetableComment
:
let vegetableComment = "Is it a spicy \(x)?"
You can see as well that x
can´t be "celery", "cucumber" or "watercress", otherwise it would give you a different outcome:
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
Because those cases are before case let x where x.hasSuffix("pepper"):
. You can try changing the order of them and pass the value "celery" to see a different outcome.
Edit:
From my understanding it creates a constant x
if x
's suffix is "pepper". The goal of creating this constant, is for you to use it after that:
let vegetableComment = "Is it a spicy \(x)?"
Edit 2:
After a bit more research, that's called value binding and it's described as:
switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This is known as value binding, because the values are “bound” to temporary constants or variables within the case’s body.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/gb/jEUH0.l
Upvotes: 19