Reputation: 46
I'm new to Swift so this might come as a noob question but I will be thankful if someone cleared the doubt because I cannot find any explanation online. While using for-in loop, sometimes the variables have not been initialized before and still there is no compiler error. Sometimes if I try to write var/let before them, it shows error- 'let' pattern cannot appear nested in an already immutable context
e.g., in the code below, why have the variables movie and releasedDate not been initialized before?
class MovieArchive {
func filterByYear(year:Int, movies:Dictionary<String, Int> ) -> [String]{
var filteredArray = [String]()
for (movie, releaseDate) in movies {
if year == releaseDate {
filteredArray.append(movie)
}
}
return filteredArray
}
}
var aiThemedMovies = ["Metropolis": 1927, "2001: A Space Odyssey": 1968, "Blade Runner": 1982, "War Games": 1983, "Terminator": 1984, "The Matrix": 1999, "A.I.": 2001, "Her": 2013, "Ex Machina": 2015]
var myArchive = MovieArchive()
myArchive.filterByYear(year: 2013
, movies: aiThemedMovies)
Thanks in advance for any help :)
Upvotes: 1
Views: 1075
Reputation: 535766
Without concerning ourselves with practical usage, let's just talk about what is syntactically legal in a for
loop. This is legal:
for var i in 1...3 { // ok
print(i)
i = 0
}
This is not legal:
for let i in 1...3 { // error
print(i)
}
Why? Because the let
is implicit when you say this:
for i in 1...3 { // ok
print(i)
}
You didn't say var
, so i
is automatically declared with let
. It's just a way of making your life simpler. Don't worry, be happy.
Upvotes: 1
Reputation: 8386
Swift does initialise movie
and releaseDate
using let
, but simplifies that initialisation so that you can just assume that they're set to the correct variables from movies
every time the loop iterates. That's why you don't need to write let before movie
and releaseDate
.
If you write var in front of the variable, you can mutate the value in the array that it points to. If it's a let, then it won't let you mutate it.
For example, if you place var in front of one of the variables, this code will change all the releaseDates
to 2000:
class MovieArchive {
func filterByYear(year:Int, movies:Dictionary<String, Int> ) -> [String]{
var filteredArray = [String]()
for (movie, var releaseDate) in movies {
releaseDate = 2000
if year == releaseDate {
filteredArray.append(movie)
}
}
return filteredArray
}
}
Upvotes: 1
Reputation: 38717
(movie, releaseDate)
is a tuple of variables. Swift allows initialising multiple variables at once using tuples.
let (movie, releaseDate) = ("Metropolis", 1927)
A for-in
loop is syntactic sugar to redeclare those constants for each element of your collection. In that case, let
is implicit.
There are other ways to get named constants with implicit let
, like using a closure:
class MovieArchive {
func filterByYear(year: Int, movies: [String: Int]) -> [String] {
return movies.filter { (movie, releaseDate) -> Bool in
year == releaseDate
}.map { $0.key }
}
}
The above example gives the same results as your code by the way.
But apart from for-in
, func parameters and closures, I can't think of other cases where the let
/var
keyword would be omitted in Swift 3.0.
Upvotes: 0