Go ステートメント編
ステートメント編
if文
基本のif文
package main import "fmt" func main(){ num := 6 // 余剰がなければ"by 2" if num % 2 == 0 { fmt.Println("by 2") }
if else文
package main import "fmt" func main(){ num := 6 // 余剰がなければ"by 2"あれば"else" if num % 2 == 0 { fmt.Println("by 2") } else { fmt.Println("else") }
else if文
pacage main import "fmt" func main() { num := 6 // 2で割って余剰がなければ"by 2" // 3で割って余剰がなければ"by 3" // 余剰があれば"else" if num % 2 == 0 { fmt.Println("by 2") } else if num % 3 == 0 { fmt.Println("by 3") } else { fmt.Println("else") } }
論理演算子
package main import "fmt" func main() { x, y := 11, 12 // 論理積(左辺も右辺もtrueの場合にtrue) if x == 10 && y ==10{ fmt.Println("&&") } // 論理和(左辺か右辺のどちらかがtrueの場合にtrue) if x == 10 || y ==10{ fmt.Println("||") } // 論理否定 if x != 10 { fmt.Println("||") }
if文 関数の呼び出し
// 2で割った際の余剰を判定 func by2(num int) string{ if num % 2 == 0 { return "ok" } else { return "no" } } func main() { // 関数を変数resultに挿入してif文を実行 result := by2(10) if result == "ok" { fmt.Println("great") } // セミコロンを使用してワンライナーで記述も可能 if result2 := by2(10); result2 == "ok"{ fmt.Println("great 2") } }
for文
for文の基本
package main import "fmt" func main(){ // i が10 以上になるまで繰り返す for i := 0; i < 10; i++ { fmt.Println(i) }
continue
package main import "fmt" // continue for i :=0; i < 10; i++ { if i == 3{ fmt.Println("continue") continue } fmt.Println(i) }
break
for i :=0; i < 10; i++ { if i == 3{ fmt.Println("continue") continue } if i > 5 { fmt.Println("break") break } fmt.Println(i) }
for文の別の書き方
sum := 1 for ; sum < 10; { sum += sum fmt.Println(sum) } fmt.Println(sum) }
;(セミコロン)の省略も可能
sum := 1 for sum < 10 { sum += sum fmt.Println(sum) } fmt.Println(sum) }
無限ループ
for { fmt.Println("hello") }
switch分
基本的なswich文
package main import "fmt" import "time" func main(){ os := "mac" switch os { case "mac": fmt.Print("Mac!!") case "windows": fmt.Print("Windows!!") default: fmt.Println("Default!!") }
defaultを省略した場合は処理がされないまま終了する
func main() { switch os { case "mac": fmt.Print("Mac!!") case "windows": fmt.Print("Windows!!") } } // >>> Process finished with exit code 0
func getOsName() string{ return "dafdaf" } func main() { switch os := getOsName(); os { case "mac": fmt.Print("Mac!!") case "windows": fmt.Print("Windows!!") default: fmt.Println("Default!!") } } // 外側で変数osを使おうとするとスコープ外でエラーになる fmt.Println(os)
switchのところで条件を書かなくても処理ができる
t := time.Now() fmt.Println(t.Hour()) switch { case t.Hour() < 12: fmt.Println("Morning") case t.Hour() < 17: fmt.Println("Afternoon") } }
defer
遅延実行
package main import "fmt" func main(){ // defer 遅延実行 main関数の処理が終わってからdeferで定義したものが動く defer fmt.Println("world") fmt.Println("hello") } // >>> hello // >>> world
deferを持っている関数を呼び出した場合はその関数内のdeferが終わってからmain関数となる
func foo() { defer fmt.Println("world foo") fmt.Println("hello foo") } func main(){ foo() defer fmt.Println("world") fmt.Println("hello") } // >>> hello foo // >>> world foo // >>> hello // >>> world
deferが並んだ場合は最後のdferから逆順に実行されてゆく
func main(){ fmt.Println("start") defer fmt.Println("1") defer fmt.Println("2") defer fmt.Println("3") fmt.Println("end") } // >>> start end 3 2 1
そもそものdeferの使いどきはいつなのか?
ファイルを取り扱う際に使用したりすることが比較的多い
*lesson.goがある想定で
func main() { file, _ := os.Open("./lesson.go") defer file.Close() data := make([]byte, 100) // バイト配列の作成 file.Read(data) //バイト配列を挿入 fmt.Println(string(data)) // stringにキャストして出力 }
log
基本的にGOはログ出力において他の言語のように INFO やERROR などを組み込んだ標準ライブラリで提供していないのでもし他言語のようにエラーハンドリングを行いたいのであればサードパーティライブラリを使用する必要がある
package main import ("log" "fmt" "os" "io" ) func loggingSettings(logFile string){ logfile, _ := os.OpenFile(logFile, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) multiLogFile := io.MultiWriter(os.Stdout, logfile) log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.SetOutput(multiLogFile) } func main(){ // 基本系 log.Println("logging!") log.Printf("%T, %v", "test", "test")
Fatal
Fatal以降は処理が終了するので後続のコードは実行されない
log.Fatalf("%T, %v", "test", "test") // 以降出力されない log.Fatalln("error!!") // 出力されない fmt.Println("ok!")
// 存在しないファイルを開こうとする _, err := os.Open("fdfdfdfd") if err != nil{ log.Fatalln("Exit", err) } // >>> Exit open fdfdfdfd: no such file or directory }
エラーハンドリング
他の言語のようにtry exceptのようにハンドリングする訳ではなく、使用した関数においてerrが返却されるものに対してひとつひとつに対してif文でエラーハンドリングするのがGoの作法としてある
package main import ("log" "os" ) func main(){ file, err := os.Open("./lesson.go") if err != nil { log.Fatalln("Error!") } defer file.Close() data := make([]byte, 100) count, err := file.Read(data) if err != nil{ log.Fatalln("Error") } fmt.Println(count, string(data)) // err 変数が2回目のshort decraretionのinisirazeとなっているが、どれかひとつinisirazeされていればエラーにならない if err = os.Chdir("test"); err != nil{ log.Fatalln("Error") } }
panicとrecover
panicやrecoverを使用することは実はあまり推奨されていない。 エラーハンドリングをきちんとしようという考えからきている
package main import "fmt" func thirdPartyConnectedDB(){ panic("Unable to connect database!") } func save(){ thirdPartyConnectedDB() defer func(){ s := recover() fmt.Println(s) } } func main(){ save() fmt.Println("OK?") } // >>> Unable to connect database ! // >>> thirdPartyConnectedDBメソッドでパニックが起こる
ThirdPartyConnectedDBメソッドでパニックが起こるが、defer 文は panic() 関数が呼ばれるかに関わらず処理される
package main import "fmt" func thirdPartyConnectedDB(){ panic("Unable to connect database!") } func save(){ defer func(){ s := recover() fmt.Println(s) } thirdPartyConnectedDB() } func main(){ save() fmt.Println("OK?") } // >>> Unable to connect database ! // >>> OK?