03. Flow Control
if
условие
if
условиеУсловное выражение if
в Go:
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
Like for
, the if
statement can start with a short statement to execute before the condition.
Variables declared by the statement are only in scope until the end of the
if
.Variables declared inside an
if
short statement are also available inside any of the else blocks.
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
return lim
}
for
loop
for
loopGo has only one looping construct, the for
loop. The basic for
loop has three components separated by semicolons:
the init statement: executed before the first iteration
the condition expression: evaluated before every iteration
the post statement: executed at the end of every iteration
for i := 0; i < 20; i++ {
fmt.Println(i)
}
Классический цикл по массиву или слайсу:
for i := 0; i < len(sl); i++ {
println("c-style loop", i, sl[i])
}
Note: Unlike other languages like C, Java, or JavaScript there are no parentheses surrounding the three components of the for
statement and the braces { }
are always required.
The init and post statement are optional. At that point you can drop the semicolons:
sum := 1
for sum < 1000 {
sum += sum
}
If you omit the loop condition it loops forever, so an infinite loop is compactly expressed.
for {
println("бесконечный цикл")
break
}
Range for
loop
for
loopThe
range
form of thefor
loop iterates over a slice, map or channel.When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.
The
range
loop evaluates the provided expression only once, before the beginning of the loop, by doing a copy (regardless of the type).When a range loop iterates over a data structure, it performs a copy of each element to the value variable (the second item). To avoid copy either use a classic for loop or a range loop using the index instead of the value variable.
Iterating over using the range loop, regardless of the number of elements, creates a single variable for the value with a fixed address. This value is being reassigned on each iteration, but it keeps the same address.
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
You can skip the index or value by assigning to _
.
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
It’s important to know that range
is making a copy of the value, not returning a reference. If you use the address of the value variable as a pointer to each element, you’ll be making a mistake.
Iterating over map you shouldn’t make any ordering assumptions at all:
It doesn’t keep the data sorted by key (a map isn’t based on a binary tree).
It doesn’t preserve the order in which the data was added.
Randomize order for each iteration.
An element being produced during the same iteration in which it’s added.
switch
switch
A switch
statement is a shorter way to write a sequence of if - else
statements. It runs the first case whose value is equal to the condition expression.
Go only runs the selected case, not all the cases that follow.
Go's switch cases need not be constants, and the values involved need not be integers.
Switch cases evaluate cases from top to bottom, stopping when a case succeeds.
the order of the
default
branch in aswitch-case
control flow block can be arbitrarySwitch without a condition is the same as switch
true
.break
inside case interrupt current casefallthrough
keyword used to indicate that next case should be proceed.fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") case "windows": if mm["flag"] == "Ok" { break // выходим из switch, чтобы не выполнять переход в другой вариант } fmt.Println("Windows.") fallthrough // переходим в следующий вариант default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) }
Case could contain multiple options:
func isShellSpecialVar(c uint8) bool {
switch c {
case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
}
Blank switch: If the switch has no expression it switches on true. It's therefore possible and idiomatic—to write an if-else-if-else
chain as a switch.
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
switch wordLen := len(word); {
case wordLen < 5:
fmt.Println(word, "is a short word!")
case wordLen > 10:
fmt.Println(word, "is a long word!")
default:
fmt.Println(word, "is exactly the right length.")
}
Favor blank switch statements over if/else chains when you have multiple related cases. Using a switch makes the comparisons more visible and reinforces that they are a related set of concerns.
Labels and goto
goto
A
goto
keyword must be followed by a label to form a statement.A label which name is not the blank identifier must be used at least once.
A
goto
statement will make the execution jump to the next statement following the declaration of the label used in thegoto
statement.if a label is declared within the scope of a variable, then the uses of the label can't appear before the declaration of the variable.
Loop:
for key, val := range mm {
println("switch in loop", key, val)
switch {
case key == "firstName" && val == "Vasily":
println("switch - break loop here")
break Loop
}
}
func main() {
i := 0
Next:
if i >= 5 {
goto Exit
}
// Create an explicit code block to
// shrink the scope of k.
{
k := i + i
fmt.Println(k)
}
i++
goto Next
Exit:
}
Метка может находится и ниже, но переход по ней не должен означать вводить новых переменых (что является side effect-ом).
Last updated
Was this helpful?