#mynavi()
#setlinebreak(on)

* 目次 [#j4af1b33]
#contents
- 参照
-- https://golang.org/doc/  (公式ドキュメント)
-- https://github.com/golang/go
- 関連
-- [[Goルーチン]]
-- [[AWS SDK for Go を使ってみる]]
// -- [[Goルーチンで並列HTTPリクエストを発行]]
-- [[GoでHTTPリクエスト送信]]
-- [[GoでExcelを読む]]

* Go言語とは [#g7f68402]
#html(<div class="pl10">)
Go言語はGoogleによって開発されているプログラミング言語で Linux、Mac、Window 等の主要OS 及び Android、iOS上でも動作する。(2016年現在)
※ Google App Engine でもサポートされている。
#html(</div>)

* インストール [#n5409608]
#html(<div class="pl10">)

https://golang.org/doc/install#install

** Mac の場合 [#s0ed9876]
#html(<div class="pl10">)
Homebrew でのインストールが可能
#myterm2(){{
brew install go
}}
※パッケージを落としてインストールする場合は https://golang.org/dl/ から取得

アップグレード
#myterm2(){{
brew upgrade go
}}

#html(</div>)

インストール時に言われた通りにPATHを通す。
$HOME/.bash_profile
#myterm2(){{
export GOPATH=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
}}

#html(</div>)

* Hello World [#f5d79ee5]
#html(<div class="pl10">)
hello.go
#mycode2(){{
package main

import "fmt"

func main() {
  fmt.Printf("Hello, World\n")
}
}}

実行
#myterm2(){{
go run hello.go
}}
#html(</div>)

* 環境変数 [#l125530b]
#html(<div class="pl10">)

| 環境変数 | 説明 |h
| GOROOT |  開発ツールのインストールPATH |
| GOPATH |  ワークディレクトリのPATH |
| GOOS | ビルドした実行ファイルを実行させるOS |
| GOARCH | ビルドした実行ファイルが実行可能なアーキテクチャ |

#html(</div>)

* 基本的な構文など [#jed80257]
#html(<div class="pl10">)

** パッケージ [#c9143e5f]
#html(<div class="pl10">)

- 自身のパッケージは package で宣言する。
- 利用するパッケージは import で宣言する。
- main以外のパッケージと格納ディレクイトリは同じ名前にする。(慣例)

#mycode2(){{
package main

import "fmt"

func main(){
    fmt.Println("Hello World")
}
}}

複数 import は以下のように記述する事も可能
#mycode2(){{
    :
import (
    "fmt"
    "encoding/json"
)
    :
}}


#html(</div>)

** 変数 [#t05f93f0]
#html(<div class="pl10">)

- 変数は var で宣言する。
- 初期値を指定した場合は型指定は省略できる。
- ローカルスコープの変数に限り、「変数名:= 式」で宣言する事も可能。(型宣言は指定不可)

#mycode2(){{
// aを宣言
var a int

// 初期値を指定してbを宣言
var b int = 1

// 初期値を指定してcを宣言(型指定を省略)
var c = 0

// 複数の変数を宣言
var d1, d2 int
var e1, e2 int = 1, 2
var f1, f2 = 1, 2

// ローカル変数の宣言例
func main(){

    // aを宣言
    var a int
    a = 1

    // bの宣言と初期化(型指定は不可)
    b := 1
}
}}

#html(</div>)

** 定数 [#s07e7f3c]
#html(<div class="pl10">)

定数は const キーワードで宣言する。
#mycode2(){{
package main

import "fmt"

const c1 string = "const1"

func main(){

    const c2 string = "const2"

    fmt.Printf("c1: %s\n", c1) 
    fmt.Printf("c2: %s\n", c2) 
}
}}

#html(</div>)


** データ型 [#m516f8ea]
#html(<div class="pl10">)

*** 数値型(整数型) [#ee15c254]
#html(<div class="pl10">)

| データ型 | 説明 |h
| int | 符号付き整数(4または8ビット) |
| int8 | 符号付き整数(8ビット) |
| int16 | 符号付き整数(16ビット) |
| int32 | 符号付き整数(32ビット) |
| int64 | 符号付き整数(64ビット) |
| uint | 符号なし整数(4 または 8ビット) |
| uint8 | 符号なし整数(8ビット) |
| uint16 | 符号なし整数(16ビット) |
| uint32 | 符号なし整数(32ビット) |
| uint64 | 符号なし整数(64ビット) |
| byte | 符号なし整数(8ビット) ※unit8と同じ |
| rune | 符号付き整数(32ビット) ※int32と同じ |
| uintptr | ポインタの値を符号なしの整数で格納 |

 
#mycode2(){{
package main

import "fmt"

func main(){
    var myInt int = 1 
    var myInt8 int8 = 1 
    var myInt64 int64 = 1 
    var myUint uint = 1 
    var myByte byte = 0x01
    var myRune rune = 0x01
    fmt.Printf("myInt   : %T\n", myInt)
    fmt.Printf("myInt8  : %T\n", myInt8)
    fmt.Printf("myInt64 : %T\n", myInt64)
    fmt.Printf("myUint  : %T\n", myUint)
    fmt.Printf("myByte  : %T\n", myByte)
    fmt.Printf("myRune  : %T\n", myRune)
}
}}

結果
#myterm2(){{
myInt   : int
myInt8  : int8
myInt64 : int64
myUint  : uint
myByte  : uint8
myRune  : int32
}}

#html(</div>)

*** 数値型(浮動小数点型) [#n2a3f143]
#html(<div class="pl10">)

| データ型 | 説明 |h
| float32 | 32ビットの浮動小数点 |
| float64 | 64ビットの浮動小数点 |
&br;
#mycode2(){{
package main

import "fmt"

func main(){
    var myFloat32 float32 = 1.234
    var myFloat64 float64 = 1.234
    fmt.Printf("myFloat32 : %T, %f\n", myFloat32, myFloat32)
    fmt.Printf("myFloat64 : %T, %f\n", myFloat64, myFloat64)
}
}}

結果
#myterm2(){{
myFloat32 : float32, 1.234000
myFloat64 : float64, 1.234000
}}

#html(</div>)

*** 数値型(複素数型) [#h8f10322]
#html(<div class="pl10">)
| データ型 | 説明 |h
| complex64 | float32型の実数+虚数 |
| complex128 | float64型の実数+虚数 |

#html(</div>)

*** 文字列 [#x2bb026d]
#html(<div class="pl10">)

#mycode2(){{
package main

import "fmt"

func main(){
    var myString string = "ABC"
    fmt.Printf("myString : %T, %s\n", myString, myString)
}
}}

結果
#myterm2(){{
myString : string, ABC
}}

#html(</div>)

*** 真偽値 [#ged0ac08]
#html(<div class="pl10">)

#mycode2(){{
package main

import "fmt"

func main(){
    var myBool bool = true
    fmt.Printf("myBool : %T, %v\n", myBool, myBool)
}
}}

結果
#myterm2(){{
myBool : bool, true
}}

#html(</div>)

*** 配列/スライス [#rf2d5d93]
#html(<div class="pl10">)

#mycode2(){{
package main

import "fmt"

func main(){

    // 数値の配列
    var array1 [2]int
    array1[0] = 1 
    array1[1] = 2 
    for i,val := range array1{
        fmt.Printf("array1[%d] = %d\n", i, val)
    }   

    // 宣言と同時に初期化
    array2 := []int{1,2}
    for i,val := range array2{
        fmt.Printf("array2[%d] = %d\n", i, val)
    }   

    // 文字列の配列
    array3 := []string{"A", "B"}
    for i,val := range array3{
        fmt.Printf("array3[%d] = %s\n", i, val)
    }   
}
}}

結果
#myterm2(){{
array1[0] = 1
array1[1] = 2
array2[0] = 1
array2[1] = 2
array3[0] = A
array3[1] = B
}}


スライスの要素追加と削除
#mycode2(){{
package main

import "fmt"

func main(){

    // スライス(配列)への要素追加
    var array = []string{"test1", "test2"}
    array = append(array, "test3")
    array = append(array, "test4")

    // スライスのN番目の要素削除
    // (削除用の関数は用意されていないので、自分で別の配列を作る)
    i := 1
    copy(array[i:], array[i+1:])
    array = array[:len(array)-1]

    for i,val := range array{
        fmt.Printf("array[%d] = %s\n", i, val)
    }   
}
}}

結果
#myterm2(){{
array[0] = test1
array[1] = test3
array[2] = test4
}}

#html(</div>)

*** マップ [#x383f665]
#html(<div class="pl10">)


#mycode2(){{
package main

import "fmt"

func main(){

    // マップの宣言と値の代入
    var map1 map[string]string = make(map[string]string)
    //var map1 map[string]string = map[string]string{}  // 上記と同義
    //map1 := map[string]string{}                       // 上記と同義
    map1["key1"] = "A" 
    map1["key2"] = "B" 
    for key,val := range map1{
        fmt.Printf("map1[%s] = %s\n", key, val)
    }   

    // 宣言と同時に初期化
    map2 := map[string]string{"key1": "C", "key2": "D"}
    for key,val := range map2{
        fmt.Printf("map2[%s] = %s\n", key, val)
    }   
}
}}

結果
#myterm2(){{
map1[key1] = A
map1[key2] = B
map2[key1] = C
map2[key2] = D
}}

#html(</div>)

*** ポインタ [#jd20d0d6]
#html(<div class="pl10">)

#mycode2(){{
package main

import "fmt"

func main(){

    num := 10
    str := "ABC"

    var p1 *int = &num      // numのアドレスを取得
    var p2 *string = &str   // strのアドレスを取得

    fmt.Printf("p1 address: %v\n", p1) 
    fmt.Printf("p1 value: %v\n", *p1)
    fmt.Printf("p2 address: %v\n", p2) 
    fmt.Printf("p2 value: %v\n", *p2)
}
}}

結果
#myterm2(){{
p1 address: 0xc000016078
p1 value: 10
p2 address: 0xc000010200
p2 value: ABC
}}

#html(</div>)

*** 構造体 [#gf5299bf]
#html(<div class="pl10">)

#mycode2(){{
package main

import "fmt"

type MyStruct struct {
    name string
    age int 
}

func main(){
    var s1 MyStruct
    s1.name = "Taro"
    s1.age  = 20
    fmt.Printf("%T, %+v\n", s1, s1) 

    var s2 = MyStruct{name: "Jiro", age: 10} 
    fmt.Printf("%T, %+v\n", s2, s2) 
}
}}

結果
#myterm2(){{
main.MyStruct, {name:Taro age:20}
main.MyStruct, {name:Jiro age:10}
}}

#html(</div>)

*** nil [#id63a35c]
#html(<div class="pl10">)

go には null は存在しない。
代わりにポインタ等が初期化されているかどうかの判断には nil が使用できる。
ちなみに string や int 等の変数には nil は代入できない。

#mycode2(){{
package main

import "fmt"

func main(){

    str := "ABCD"

    var p1 *string
    if p1 == nil {
        p1 = &str
        fmt.Println("p1 set!")
    }   
    fmt.Printf("%T, %+v\n", p1, *p1)
}
}}

結果
#myterm2(){{
p1 set!
*string, ABCD
}}

#html(</div>)


#html(</div>)


** 型宣言 [#v147f939]
#html(<div class="pl10">)

type を使用する事で、型に別名を付けて新しい型を作成する事ができる。

#mycode2(){{
package main

import "fmt"

type MyInt int 

type MyStruct struct {
    Id MyInt
    Name string
}

func main(){
    x := MyStruct{Id: 100, Name: "Taro"}
    fmt.Printf("Id: %d\n", x.Id)
    fmt.Printf("Name: %s\n", x.Name)
}
}}

#html(</div>)


** 条件分岐 [#r1e59357]
#html(<div class="pl10">)

*** if による条件分岐 [#x7fff487]
#html(<div class="pl10">)
#mycode2(){{
package main

import "fmt"

func main(){

    x := 3

    if x == 1 { 
        fmt.Println("x is 1")
    } else if x == 2 { 
        fmt.Println("x is 2")
    } else {
        fmt.Println("others")
    }   
}
}}
#html(</div>)

*** switch による条件分岐 [#ud1039bd]
#html(<div class="pl10">)

他の言語と同様に switch も使用できる。
ただし Java等と違って break を書く必要がない点が異なる。
逆に、次の case に遷移させたい場合は、fallthrough を使用する。

#mycode2(){{
package main

import "fmt"

func main(){

    x := 3

    switch x { 
    case 1:
      fmt.Println("x is 1")
    case 2:
      fmt.Println("x is 2")
    case 3:
      fmt.Println("x is 3")
      fallthrough
    default:
      // x = 3 の時だけここが実行される
      fmt.Println("others")
    }

    // 以下の書き方も可能
    switch {
    case x == 1:
      fmt.Println("x is 1")
    case x == 2:
      fmt.Println("x is 2")
    case x == 3:
      fmt.Println("x is 3")
    }
}
}}
#html(</div>)

#html(</div>)

** 繰り返し [#i8ffcf5f]
#html(<div class="pl10">)

繰り返しは全て for で行う。
while や foreach は存在しないが、同等の処理を for のみで行う事が可能となっている。

#mycode2(){{
package main

import "fmt"

func main(){

    // 通常のforループ
    for i := 0; i < 5; i++ {
        fmt.Printf("i = %d\n", i)
    }

    // 疑似while
    x := 0
    for x < 5 { 
        fmt.Printf("x = %d\n", x)
        x++
    }

    // 永久ループ
    y := 0
    for {
        fmt.Printf("y = %d\n", y)
        y++ 
        if y >= 5 { 
            break
        }
    }

    // 配列要素分繰り返し(疑似foreach)
    array1 := []int{1,2,3,4,5}
    for i, val := range array1 {
        fmt.Printf("val[%d] = %d\n", i,val)
    }

    // マップの要素分繰り返し(疑似foreach)
    m := map[string]int{"k1": 1, "k2": 2, "k3": 3, "k4": 4, "k5": 5}
    for key, val := range m { 
        fmt.Printf("val[%s] = %d\n", key,val)
    }
}
}}

#html(</div>)

** 関数 [#i345716b]
#html(<div class="pl10">)

- 関数は func で宣言する。
- 他のパッケージに公開する関数は、頭の1文字目を大文字にする。
- 複数の戻り値を返却する事も可能。
- 可変長引数を受け取る事も可能。
- 関数の終了処理を defer で定義する事ができる

#mycode2(){{
package main

import "fmt"

// 通常の関数
func myAdd(a int, b int) int{
    result := a + b 
    return result
}

// 他パッケージに公開する関数
func MyAdd(a int, b int) int {
    return myAdd(a, b)
}

// 戻り値が2つの関数
func multiResult() (int, int){
    return 1, 10
}

// 可変長引数を受け取る関数
func multiArgs(a string, args...string){

    // 関数の終了処理を defer で定義する事ができる
    defer func() {
        fmt.Println("multiArgs end!")
    }()

    fmt.Printf("a = %s\n", a)
    for i, val := range args {
        fmt.Printf("args[%d] = %s\n", i, val)
    }   
}


func main(){

    result := myAdd(1, 2)
    fmt.Printf("myAdd(1,2) = %d\n", result)

    x1, x2 := multiResult()
    fmt.Printf("multiResult() = %d, %d\n", x1, x2) 

    multiArgs("a", "b", "c", "d")
}
}}

#html(</div>)


**インターフェース [#p9191eb1]
#html(<div class="pl10">)

メソッドの集まりをインターフェースとして宣言する事ができる。
これを利用して宣言すべきメソッドを定義する事が可能。

#mycode2(){{
package main

import "fmt"

// インターフェースの宣言
type Person interface {
    greet()
}

// 構造体の宣言
type PersonAttr struct {
    name string
}
// インターフェースに応じたメソッドの宣言
func (attr PersonAttr) greet(){
    fmt.Printf("Hello! My name is %s\n", attr.name)
}

func main(){
    attr := PersonAttr{name: "Taro"}
    var p Person = attr
    p.greet()
}
}}

実行結果
#myterm2(){{
Hello! My name is Taro
}}

メソッドが実装されていない時はビルドエラーとなる。
#mycode2(){{
package main

import "fmt"

// インターフェースの宣言
type Person interface {
    greet()
    hello()   // メソッドを追加
}

// 構造体の宣言
type PersonAttr struct {
    name string
}
// インターフェースに応じたメソッドの宣言
func (attr PersonAttr) greet(){
    fmt.Printf("Hello! My name is %s\n", attr.name)
}

func main(){
    attr := PersonAttr{name: "Taro"}
    var p Person = attr
    p.greet()
}
}}

実行結果
#myterm2(){{
# command-line-arguments
./test_interface.go:22:9: cannot use attr (type PersonAttr) as type Person in assignment:
	PersonAttr does not implement Person (missing hello method)
}}


#html(</div>)

** 例外処理 [#z50427ec]
#html(<div class="pl10">)

*** panic発生時の挙動 [#hb04a817]
#html(<div class="pl10">)

panic 関数が実行されると panic呼び出し以降の処理を中断し、コールスタックを巻き戻す。

#mycode2(){{
package main

import "fmt"

func func1() int {
    panic("func1 error!\n");
    return 10
}

func main(){
    fmt.Println("main start")
    res := func1()
    fmt.Printf("result = %+v\n", res)
    fmt.Println("main end")
}
}}

実行結果
#myterm2(){{
main start
panic: func1 error!


goroutine 1 [running]:
main.func1(...)
	/path_to/test_panic.go:14
main.main()
	/path_to/test_panic.go:21 +0x96
exit status 2
}}
#html(</div>)

*** recover によるコールスタック巻き戻しの停止 [#l11d8686]
#html(<div class="pl10">)

recover 関数は panic関数の引数を返し、コールスタックの巻き戻しを停止する。
#mycode2(){{
package main

import "fmt"

func func1() int {
    defer func(){
        err := recover()
        if err != nil {
            fmt.Printf("error!! ... %+v", err)
        }   
    }() 
    panic("func1 error!\n");
    return 10
}


func main(){
    fmt.Println("main start")
    res := func1()
    fmt.Printf("result = %+v\n", res)
    fmt.Println("main end")
}
}}

実行結果
#myterm2(){{
main start
error!! ... func1 error!
result = 0
main end
}}
#html(</div>)

*** ライブラリを利用する場合 [#t6f8f5f8]
#html(<div class="pl10">)

大方のライブラリでは戻り値で error も返却される為、これをエラー判定に利用する。
#mycode2(){{
f, err := os.Open("filename.ext")
if err != nil {
    // エラー処理
    log.Fatal(err)
}
}}
#html(</div>)

*** 自前の関数の実装時 [#r42d6824]
#html(<div class="pl10">)

自前のライブラリ/関数を実装する際も必要に応じて、戻り値として error  を返すインターフェースを採用する。
#mycode2(){{
package main

import "errors"
import "fmt"

func myDiv(a int, b int) (int, error) {
    if b == 0 { 
        return 0, errors.New("divide by zero")
    }   
    result := a / b 
    return result, nil 
}

func main(){
    res, err := myDiv(10, 0)
    if err != nil {
        fmt.Printf("Error!! ... %+v\n", err)
    } else {
        fmt.Printf("result = %v\n", res)
    }   
}
}}

実行結果
#myterm2(){{
Error!! ... divide by zero
}}

#html(</div>)

#html(</div>)

** Goルーチン [#nec2b113]
#html(<div class="pl10">)
[[Goルーチン]] を参照
#html(</div>)


#html(</div>)

* ビルド [#ke012467]
#html(<div class="pl10">)

** ビルド時に指定する環境変数 [#cad1dd78]
#html(<div class="pl10">)
GOOS、GOARCH を使用してターゲットとなる OS、アーキテクチャを指定する事ができる。
#myterm2(){{
GOOS=linux GOARCH=amd64 go build -o main main.go
}}

GOOS 等を省略した場合は現在の環境用にビルドされる
#myterm2(){{
go build -o main main.go
}}
#html(</div>)

** パッケージのビルド [#r371debc]
#html(<div class="pl10">)

ビルドしたパッケージで利用しているパッケージは実行ファイルに含まれる為、基本的に利用側のメイン処理をビルドするだけでOK?(TODO: 要調査)

フォルダ作成
#myterm2{{
 .
├── pkg
├── src
│&#160;&#160; ├── main.go
│&#160;&#160; ├── mypkg1
│&#160;&#160; │&#160;&#160; └── mypkg1.go
│&#160;&#160; │&#160;&#160; └── other.go
}}

src/main.go
#mycode2(){{
package main

import "mypkg1"

func main(){
    mypkg1.PrintInfo()
    mypkg1.OtherModule()
}
}}

src/mypkg1/mypkg1.go
#mycode2(){{
package mypkg1

import "fmt"

func PrintInfo() {
    fmt.Println("This is mypkg1.PrintInfo!")
}
}}

src/mypkg1/other.go
#mycode2(){{
package mypkg1

import "fmt"

func OtherModule() {
    fmt.Println("This is mypkg1.OtherModule!")
}
}}

ビルド
#myterm2(){{
go build -o pkg/main src/main.go
}}

ビルドした処理を実行
#myterm2(){{
./pkg/main
This is mypkg1.PrintInfo!
This is mypkg1.OtherModule!
}}

#html(</div>)


#html(</div>)

* 実装メモ [#jd31ecd2]
#html(<div class="pl10">)

** コマンドライン引数を取得する [#z9f7f269]
#html(<div class="pl10">)

#mycode2(){{
package main

import "flag"
import "fmt"

func main(){
    flag.Parse()
    args := flag.Args()
    for i := 0; i < len(args); i++ {
        fmt.Printf("args[%d] : %s\n", i, args[i])
    }   
}
}}

実行結果
#myterm2(){{
$ go run sample_comargs.go ABC DEF GHI
args[0] : ABC
args[1] : DEF
args[2] : GHI
}}

#html(</div>)


#html(</div>)


* ブラウザ上でGoのソースを実行する [#t2393a61]
#html(<div class="pl10">)

ブラウザ上で書いたソースを実行する環境が公式で提供されている。(無料)

Go Playground
https://play.golang.org

A Tour of Go
https://tour.golang.org

#html(</div>)

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS