A Tour of Go やってみた Part2
前回
「A Tour of Go」の"Basics: Packages, variables, and functions" までを終わらせたので、今回は "Basics: Flow control statements: for, if, else, switch and defer" をやる
Basics: Flow control statements: for, if, else, switch and defer
1. For
forはごくごく一般的な 「初期化; 条件式; インクリメント」で書くだけ。カッコで括る必要はないけど、中括弧でブロックを指定する必要がある。初期化時に短い変数宣言がよく使われる。またこの変数はforのスコープ内でのみ有効になる。
package main
import "fmt"
func main() {
sum := 0
fmt.Println("Start:", sum)
for i := 0; i< 10; i++ {
sum += 1
fmt.Println("Current:", sum)
}
fmt.Println("End:", sum)
}
Start: 0
Current: 1
Current: 2
Current: 3
Current: 4
Current: 5
Current: 6
Current: 7
Current: 8
Current: 9
Current: 10
End: 10
2. For continued
初期化と後処理は任意なので書かないことも可能。
package main
import "fmt"
func main() {
sum := 1
fmt.Println("Start:", sum)
for ; sum < 10; {
sum += sum
fmt.Println("Current:", sum)
}
fmt.Println("End:", sum)
}
Start: 1
Current: 2
Current: 4
Current: 8
Current: 16
End: 16
3. For is Go's "while"
セミコロンを省略すると、一般的なwhile
とおなじになる。
package main
import "fmt"
func main() {
sum := 1
fmt.Println("Start:", sum)
for sum < 10 {
sum += sum
fmt.Println("Current:", sum)
}
fmt.Println("End:", sum)
}
Start: 1
Current: 2
Current: 4
Current: 8
Current: 16
End: 16
4. Forever
何も条件を指定せずfor
だけだと無限ループになる。
package main
import "fmt"
func main() {
sum := 1
fmt.Println("Start:", sum)
for {
sum += 1
fmt.Println("Current:", sum)
}
}
停止条件がないのでctrl+cで止める。
Start: 1
Current: 2
Current: 3
Current: 4
Current: 5
Current: 6
Current: 7
Current: 8
Current: 9
Current: 10
(snip)
5. If
forと同じく条件をカッコで括る必要はない
package main
import (
"fmt"
"math"
)
func sqrt(x float64) string {
// 負の数の場合、虚数部分を追加
if x < 0 {
return sqrt(-x) + "i"
}
// 平方根を計算して文字列に変換
return fmt.Sprint(math.Sqrt(x))
}
func main() {
fmt.Println(sqrt(2), sqrt(-4))
}
1.4142135623730951 2i
6. If with a short statement
ifもforと同じ初期化ステートメントが使えて、ここで初期化された変数はifのスコープ内だけ有効になる。
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
// 変数vはifスコープ内でのみ有効
// xのn乗を計算して、それがlimより小さいか
if v := math.Pow(x, n); v < lim {
return v
}
// ここではvは使えない
return v
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
# command-line-arguments
./6.go:12:9: undefined: v
これなら動くのでスコープが有効なことがわかる。
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
v := math.Pow(x, n)
if v < lim {
return v
}
return -v
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
9 -27
7. If and else
if {〜} else {〜}
という形。ifで初期化された変数はelse内でも使える。
package main
import (
"fmt"
"math"
)
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
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
27 >= 20
9 20
8. Exercise: Loops and Functions
Exerciseはパス
9. Switch
選択されたcaseだけが実行されてそれ以外は実行されない、よってbreakを書く必要がない。また、ラベルに変数や計算式を直接書いてもよいし、整数以外の型(文字列、浮動小数点、さらにはユーザー定義型など)も使える。
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
os := runtime.GOOS
switch os {
case "darwin":
fmt.Print("macOS")
case "linux":
fmt.Print("Linux")
default:
fmt.Print("%s", os)
}
arch := runtime.GOARCH
switch arch {
case "amd64":
fmt.Println("/AMD64.")
case "386":
fmt.Println("/386.")
case "arm64":
fmt.Println("/ARM64.")
default:
fmt.Printf("/%s.\n", arch)
}
}
自分の場合はM2 Macなので。
Go runs on macOS/ARM64.
10. Switch evaluation order
switch caseは上から順に評価し、caseが一致すればそこで停止する。
package main
import "fmt"
func f() int {
fmt.Println("f() called. return 1")
return 1
}
func main() {
i := 0
switch i {
case 0:
fmt.Println("case 0")
case f():
fmt.Println("case f()")
}
}
評価すらされていないということか。
case 0
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("土曜日はいつですか?")
today := time.Now().Weekday()
fmt.Println(today, time.Saturday)
switch time.Saturday {
case today + 0:
fmt.Println("今日です。")
case today + 1:
fmt.Println("明日です。")
case today + 2:
fmt.Println("明後日です。")
default:
fmt.Println("まだ先です。。。")
}
}
土曜日はいつですか?
Tuesday Saturday
まだ先です。。。
11. Switch with no condition
条件無しで書くこともできる。if-then-elseをシンプルに書ける。
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("おはよう!")
case t.Hour() < 17:
fmt.Println("こんにちは!")
default:
fmt.Println("こんばんは!")
}
}
こんにちは!
12. Defer
deferに関数を渡すと、defer呼び出し元の関数が終了(return)するまで遅延させることができる。評価自体はdeferのタイミングで行われるが、実行は呼び出し元関数が終了してから。
package main
import "fmt"
func main() {
defer fmt.Println("遅れて実行されます。")
fmt.Println("こんにちは。")
}
こんにちは。
遅れて実行されます。
13. Stacking defers
deferに複数の関数を渡すと、呼び出しがスタックされて、呼び出し元がreturnしたタイミングでLIFOで実行される。
package main
import "fmt"
func main() {
fmt.Println("数えます")
for i :=0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("終了しました")
}
開始します
終了しました
9
8
7
6
5
4
3
2
1
0
続き