目次

Go言語とは

Go言語はGoogleによって開発されているプログラミング言語で Linux、Mac、Window 等の主要OS 及び Android、iOS上でも動作する。(2016年現在)
※ Google App Engine でもサポートされている。

インストール

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

Mac の場合

Homebrew でのインストールが可能

brew install go

※パッケージを落としてインストールする場合は https://golang.org/dl/ から取得

インストール時に言われた通りにPATHを通す。
$HOME/.bash_profile

export GOPATH=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin

Hello World

hello.go

package main

import "fmt"

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

実行

go run hello.go

環境変数

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

基本的な構文など

パッケージ

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

import "fmt"

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

複数 import は以下のように記述する事も可能

    :
import (
    "fmt"
    "encoding/json"
)
    :

変数

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

定数

定数は const キーワードで宣言する。

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) 
}

データ型

数値型(整数型)

データ型説明
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ポインタの値を符号なしの整数で格納

 

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)
}

結果

myInt   : int
myInt8  : int8
myInt64 : int64
myUint  : uint
myByte  : uint8
myRune  : int32

数値型(浮動小数点型)

データ型説明
float3232ビットの浮動小数点
float6464ビットの浮動小数点


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)
}

結果

myFloat32 : float32, 1.234000
myFloat64 : float64, 1.234000

数値型(複素数型)

データ型説明
complex64float32型の実数+虚数
complex128float64型の実数+虚数

文字列

package main

import "fmt"

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

結果

myString : string, ABC

真偽値

package main

import "fmt"

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

結果

myBool : bool, true

配列/スライス

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)
    }   
}

結果

array1[0] = 1
array1[1] = 2
array2[0] = 1
array2[1] = 2
array3[0] = A
array3[1] = B

マップ

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)
    }   
}

結果

map1[key1] = A
map1[key2] = B
map2[key1] = C
map2[key2] = D

ポインタ

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)
}

結果

p1 address: 0xc000016078
p1 value: 10
p2 address: 0xc000010200
p2 value: ABC

構造体

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) 
}

結果

main.MyStruct, {name:Taro age:20}
main.MyStruct, {name:Jiro age:10}

nil

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

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)
}

結果

p1 set!
*string, ABCD

型宣言

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

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)
}

条件分岐

if による条件分岐

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")
    }   
}

switch による条件分岐

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

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")
    }
}

繰り返し

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

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)
    }
}

関数

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

インターフェース

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

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()
}

実行結果

Hello! My name is Taro

メソッドが実装されていない時はビルドエラーとなる。

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()
}

実行結果

# 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)

例外処理

panic発生時の挙動

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

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")
}

実行結果

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

recover によるコールスタック巻き戻しの停止

recover 関数は panic関数の引数を返し、コールスタックの巻き戻しを停止する。

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")
}

実行結果

main start
error!! ... func1 error!
result = 0
main end

ライブラリを利用する場合

大方のライブラリでは戻り値で error も返却される為、これをエラー判定に利用する。

f, err := os.Open("filename.ext")
if err != nil {
    // エラー処理
    log.Fatal(err)
}

自前の関数の実装時

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

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)
    }   
}

実行結果

Error!! ... divide by zero

Goルーチン

Goルーチン を参照

ビルド

ビルド時に指定する環境変数

GOOS、GOARCH を使用してターゲットとなる OS、アーキテクチャを指定する事ができる。

GOOS=linux GOARCH=amd64 go build -o main main.go

GOOS 等を省略した場合は現在の環境用にビルドされる

go build -o main main.go

パッケージのビルド

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

フォルダ作成

 .
├── pkg
├── src
│   ├── main.go
│   ├── mypkg1
│   │   └── mypkg1.go
│   │   └── other.go

src/main.go

package main

import "mypkg1"

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

src/mypkg1/mypkg1.go

package mypkg1

import "fmt"

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

src/mypkg1/other.go

package mypkg1

import "fmt"

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

ビルド

go build -o pkg/main src/main.go

ビルドした処理を実行

./pkg/main
This is mypkg1.PrintInfo!
This is mypkg1.OtherModule!

ブラウザ上でGoのソースを実行する

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

Go Playground
https://play.golang.org

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


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS