3

I see difference but i don't get it (I don't know how to read code with understanding it)

var abc = ["A", "B", "C", "D"]
var number = ["1", "2", "3"]

for i in 0 ..< abc.count {
    var str = "\(abc[i])"
    
    for _ in 0..<2{
        str += " \(number[i])"
    }
    
    print(str)
} /* output:   A11
               B22
               C33
 Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
 */

when code has 'i' instead of '_' in nested for loop:

var abc = ["A","B","C","D"]
var number = ["1","2","3"]

for i in 0..<abc.count {
    var str = "\(abc[i])"

    for i in 0..<2{
        str += " \(number[i])"
    }

    print(str)
}
/* output: A 1 2
           B 1 2
           C 1 2
           D 1 2
 */
Max Play
  • 3,717
  • 1
  • 22
  • 39
Dzondzula
  • 81
  • 1
  • 8

3 Answers3

6

The underscore (in this situation) tells the compiler that there is something there, but you don't need access to it in your code by name. There's a link with more details in the comments to your question, but let's look at the effect it has on the code in question.

Seeing the code formatted might help it to be more clear:

var abc = ["A", "B", "C", "D"]
var number = ["1", "2", "3"]

for i in 0 ..< abc.count {
    var str = "\(abc[i])"
    
    for _ in 0..<2 {
        str += " \(number[i])"
    }
    print(str)
}

In this example, the outer for loop stores its index in I. The inner for loop has an index, but the _ is basically saying (I'm okay ignoring this for now). The loop still runs, but the index isn't being used anywhere.

The reason this results in a runtime error is because abc has more elements than number. So, when the inner loop tries to access number[3] when i is 3, there's a crash.


Now, let's look at the second example:

var abc = ["A","B","C","D"]
var number = ["1","2","3"]

for i in 0..<abc.count {
    var str = "\(abc[i])"
    
    for i in 0..<2 {
        str += " \(number[i])"
    }
    print(str)
}

In this example, i is used in both the outer and inner loops. This is sometimes called variable shadowing and is generally a bad idea, because it can lead to very confusing situations where it's easy to mistake what variable is being read. For example, here, in the scope of the outer loop, i means one thing, but then in the scope of the inner loop, it means something else.

It would be more clear like this:

for i in 0..<abc.count {
    var str = "\(abc[i])"
    
    for j in 0..<2 {
        str += " \(number[j])"
    }
    print(str)
}

Now, on the outer loop, i is the index and on the inner one j is the index.


The two examples may look very similar, but really they function very differently because of the details of how the indexes are used within the loops.

aheze
  • 24,434
  • 8
  • 68
  • 125
jnpdx
  • 45,847
  • 6
  • 64
  • 94
4

From Swift Documentation

If you don’t need each value from a sequence, you can ignore the values by using an underscore in place of a variable name

The underscore character (_) used in place of a loop variable causes the individual values to be ignored and doesn’t provide access to the current value during each iteration of the loop.

AnderCover
  • 2,488
  • 3
  • 23
  • 42
2

Underscore denotes a “discarded” value. “Discarded” meaning that you don’t intent to use the loop counter value within the loop, so you don’t declare a variable.

Otherwise, if you would declare a loop counter variable like, e.g. for j in 0..<2, the Swift compiler would complain you have a declared but unused variable j.

Alexander
  • 59,041
  • 12
  • 98
  • 151
emirc
  • 1,948
  • 1
  • 23
  • 38