うおのめマリーの満遊記

都会の団地でプー太郎をしているエンジニアの日常。たまに軽く仕事とったりしながらまったりとスローライフを満喫中。料理が得意です。

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?