- 追加された行はこの色です。
- 削除された行はこの色です。
- Go言語 へ行く。
#author("2025-01-19T10:03:52+09:00","","")
#mynavi()
#setlinebreak(on)
* 目次 [#j4af1b33]
#contents
- 参照
-- https://golang.org/doc/ (公式ドキュメント)
-- https://github.com/golang/go
- 関連
-- [[Goルーチン]]
-- [[AWS SDK for Go を使ってみる]]
-- [[Azureからのメール送信(SendGird使用)]]
// -- [[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>)
** クラス [#d0ab4db5]
#html(<div class="pl10">)
interface と struct を利用してクラスを実装する事が出来る。
#mycode2(){{
import (
"fmt"
)
// 基底クラスのインターフェース
type MyBaseIf interface {
Print(msg string)
}
// 基底クラスの実装
type MyBaseImpl struct {
typeName string
MyBaseIf
}
func (wrapper *MyBaseImpl) Print(msg string) {
fmt.Printf("これは基底クラスのメソッドです typeName: %s, message: %s\n", wrapper.typeName, msg)
}
// 継承クラスの実装
type MySample1Impl struct {
etcName string
MyBaseImpl
}
func (wrapper *MySample1Impl) Print(msg string) {
fmt.Printf("これは継承クラスのメソッドです typeName: %s, etcName: %s, message: %s\n", wrapper.typeName, wrapper.etcName, msg)
}
func getInstance(typeName string) MyBaseIf {
if typeName == "sample1" {
obj := &MySample1Impl{}
obj.typeName = typeName
obj.etcName = "this is sample1"
return obj
} else {
return &MyBaseImpl {typeName: typeName}
}
}
obj := getInstance("sample1")
obj.Print("test1")
obj := getInstance("other")
obj.Print("test1")
}}
実行結果
#myterm(){{
これは継承クラスのメソッドです typeName: sample1, etcName: this is sample1, message: test1
これは基底クラスのメソッドです typeName: other, message: test1
}}
#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
│   ├── main.go
│   ├── mypkg1
│   │   └── mypkg1.go
│   │   └── 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>)