###### range-over-args.go ```go package main import ( "fmt" "os" ) func main() { args := os.Args[1:] for i, arg := range args { fmt.Println(i+1, arg) } } ``` ``` $ go run range-over-args.go foo bar 1 foo 2 bar ``` ## Slice The program takes a slice of the default `Args` slice to skip over the first argument at index 0, which is always the full pathname of the command. The bracket notation below specifies taking a slice starting at index 1 until the end of `os.Args`. [^1] If there is an element accessible at index 1 of the original slice, `os.Args`, it will now be accessible at index 0 of the new slice, assigned to `args`. ```go args := os.Args[1:] ``` ## Short Variable Declarations The snippet demonstrates a *short variable declaration* [^2], a standard Go idiom used in place of a more verbose form or even separate declaration and assignment statements. ```go // Instead of this... var args []string args = os.Args // Or this... var args []string = os.Args // Or even this (type automatically inferred)... var args = os.Args // Use short variable declarations instead. // Idiomatic, but only works inside of functions. // Type automatically inferred. args := os.Args ``` ## Looping with the Range Clause Go has only one looping construct and it's based on the `for` keyword. In Go, the idiomatic way to loop over types that can be iterated (including standard arrays, slices, strings, maps, and channels) is to use a range clause, as shown In this snippet. ```go for i, arg := range args { fmt.Println(i+1, ": ", arg) } ``` For arrays and slices, range yields two values for each element: the index and the element at that index. These values can be assigned to variables using short variable declaration syntax. In this example, they are assigned to `i` and `arg`, respectively. ## Discarding Values A common idiom when the index value value of the yielded element itself isn't needed is to use `_` in place of a variable name for the assignment. This is because Go doesn't allow any declared name to go unused, so `_` provides the ability to indicate that discarding the value is intentional. ```go // ignore the index value for _, arg := range args { fmt.Println(arg) } ``` ## Loop syntax in more detail In general, for anything in Go that returns multiple values, you only need to use the underscore as a placeholder to skip a positional value so that you can correctly assign other remaining positional values to variables. If you're not interested in any remaining values after a particular position, you don't need to do anything to ignore them. For this example then, if you only need to declare `i` for the index variable, it isn't necessary to use an underscore to ignore the following value for the element: ```go // ignore the element value for i := range args { fmt.Println(i+1, args[i]) } ``` If for some reason you simply wanted to loop based on the length of args, ignoring *all* values, you can simply dispense with range variable assignments altogether: ```go i := 0 // ignore both the index and element values for range args { // Increment and decrement statement: // i++ <==> i += 1 <==> i = i + 1 // i-- <==> i -= 1 <==> i = i - 1 // Can't be used in an expression. // No pre-increment/decrement support. i++ fmt.Println(i) } ``` Or just use `for` all by itself: ```go i := 0 for { // Loop exit condition. if i == len(args) { break } fmt.Println(i+1, args[i]) i++ } ``` You can always use the basic (classic, canonical C-style) for loop with an *init* statement, *condition* expression, and *post* statement: ```go for i := 0; i < len(args); i++ { fmt.Println(i+1, args[i]) } ``` Any of the three clauses in the for loop can be omitted. Semicolons must still be present as placeholders, unless there is only a single clause, which must be the condition clause: ```go i := 0 for i < len(args) { fmt.Println(i+1, args[i]) i++ } ``` --- Next: [[7. Command Flags]] [^1]: Slices are very efficient in Go. Internally, a slice is a small struct that points to the underlying array elements while tracking the start, length, and capacity of the slice. [^2]: Also referred to as *short statement assignments*. Type is automatically inferred. Can only be used inside functions. See: https://go.dev/ref/spec#Short_variable_declarations