技術めも

study golang memo

逆引きGolang
http://ashitani.jp/golangtips/index.html

Go言語 例文辞典 v1.1.1
http://www.openspc2.org/reibun/Go/1.1.1/

Go言語のstringsパッケージを試してみた
http://y0m0r.hateblo.jp/entry/20120917/1347892585
http://golang.jp/pkg/strings

さあGoを始めよう!環境構築,”Hello World”から簡単なバックエンドサーバーまで
http://postd.cc/how-i-start-go/

Go Con 2017スライドまとめと感想
http://tikasan.hatenablog.com/entry/2017/03/25/225619

net/httpで作るGo APIサーバー #1
http://akirachiku.com/2017/04/01/go-net-http-api-server-1.html

Go言語のFunctional Option Pattern
http://qiita.com/weloan/items/56f1c7792088b5ede136

http://dotinstall.com/lessons/basic_golang

http://golang.org
sudo yum install golang
package main

import "fmt"

func main() {
    fmt.Println("hello world")
}
go build hello.go
./hello

go run hello.go

変数

import "fmt"

// 変数名:1文字目に注意

func main() {
    var msg string
    msg = "hello world"
    
    var msg = "hello world"
    
    msg := "hello world" // 変数と値の入力
    
    var a, b int
    a , b = 10 , 15
    
    a, b := 10, 15
    
    // 型が違う文字を一度に設定
    var (
        c int
        d string
    )
    
    fmt.Println(msg)
}
string      "hello"
int         53
float64     10.2
bool        true/false
nil

初期値

var s string    // ""
var a int       // 0
var f bool      // false

fmt.Println()

a := 10
b := 12.5
c := "hello"
var d bool

fmt.Printf("a: %d, b %f, c: %s, d: %t\n", a, b, c, d)
%v で自動で判断

定数

const name = "taguchi"
name = "hoge" // エラー

イオタ
const (
    sun = iota // 0
    mon        // 1
    tue        // 2
)

演算

数値   + - + / %
文字列 + 
論理値 AND(&&) OR (||) NOT(!)

x += 3 // x = x + 3
x++    // ++x は不可

ポインタ
アドレスを指し示す。演算は出来ない

  • ポインタ型: * で実体にアクセス
  • 実体: & で番地に変換
a := 5
var pa *int
pa = &a // &a = aのアドレス
// pa の領域にあるデータの値 = *pa

fmt.Println(pa)
fmt.Println(*pa)

関数

func hi(name string) string {
    fmt.Prinln("Hi! " + name)
    msg : = "Hi! " + name
    return msg
}
    ↓
func hi(name string) (msg string) {
    fmt.Prinln("Hi! " + name)
    msg : = "Hi! " + name
    return
}

func main() {
    fmt.Println(hi("taguchi"))
}

関数2

func swap(a, b int) (int, int) {
    return b, a
}

func main() {
    fmt.Println(swap(5, 2))
    
    f := func(a, b int) (int, int) {
        return b, a
    }

    fmt.Println(f(2, 3))

    // 即時関数
    func(msg string) {
        fmt.Println(msg)
    }("taguchi")
}

配列

var a [5]int // a[0] - a[4]  (添字は0から, 0初期化)
a[2] = 3
a[4] = 10


b := [3]int{1, 3, 5}
    ↓個数は自明
b := [...]int{1, 3, 5}

fmt.Println(a)

fmt.Println(b)
fmt.Println(len(b))

スライス:配列への参照
可変長配列を持たない代わりに実装された型
配列全体のポインタ(ptr)、配列の長さ(len)、配列の容量(cap)からなるデータ構造を保持している

a := [5]int{2, 10, 8, 15, 4}
s := a[2:4] // [8, 15] 2から4未満までを取得
s := a[:4]
s := a[2:]
s := a[:]

s[1] = 12 // aの値も変更される(参照なので)

fmt.Println(a)
fmt.Println(b)

fmt.Println(b)
fmt.Println(cap(s)) // 切り出しうる最大個数 8, 15, 4 (8からスタートなので)

スライス make(), append(), copy()

// いきなりスライス作成
s := make([]int, 3) // [0 0 0] のスライス
s := []int{1, 3, 5} // [1 3 5] のスライス(要素数を入れないとスライスになる)

// スライスの末尾に値を追加(勝手に領域拡張)
s = append(s, 8, 2, 10)

// copy
t := make([]int, len(s))
n := copy(t, s) // コピーした要素数が n に入る


fmt.Println(s)

マップ(連想配列)

m := make(map[string]int) // キーがstring,値がint
m["taguchi"] = 200
m["fkoji"] = 300

fmt.Println(m)


m := map[string]int{"taguchi":100, "fkoji":200}

fmt.Println(m)
fmt.Println(len(m)) // 個数

delete(m, "taguchi") // 削除

fmt.Println(m)
fmt.Println(len(m)) // 個数

// 存在チェック
v, ok := m["fkoji"]

fmt.Println(v)  // 200
fmt.Println(ok) // true 存在している

if 文
> >= < <= == != && || !

score := 83

if score > 80 {
    fmt.Println("Great!")
} else if score > 60 {
    fmt.Println("Good!")
} else {
    fmt.Println("so so...")
}

// if文の中だけで有効な値も定義可能
if score := 83; score > 80 {
    fmt.Println("Great!")
} else if score > 60 {
    fmt.Println("Good!")
} else {
    fmt.Println("so so...")
}

fmt.Println(score) // エラー

switch 文

signal := "red"

switch signal {
    case "red":
         fmt.Println("Stop")
    case "yellow":
         fmt.Println("Caution")
    case "green", "blue":       // カンマで複数指定
         fmt.Println("Go")
    default:
         fmt.Println("wrong signal")
}


score := 83

swith {
    case score > 80:   // 条件式が書ける
        fmt.Println("Great!")
    default:
        fmt.Println("so so...")
}

for 文

for i := 0; i < 10; i++ {
     if i == 3 { break }
     if i == 7 { continue }
     fmt.Println(i)
}

i := 0
for i < 10 {
     fmt.Println(i)
     i++
}

// 無限ループ
for {
    if i == 3 { break }
}

range

s := []int{2, 3, 8}

for i, v := range s {
    fmt.Println(i, v) // 0 2 -> 1 3 -> 2 8
}

for _, v := range s { // ブランク修飾子
    fmt.Println(v)
}

m := map[string]int{"taguchi":200, "fkoji":300}

for k, v := range m {
    fmt.Println(k, v) // taguchi 200 -> fkogi 300
}

構造体

type user struct {
    name string   // フィールド
    score int
}

// 初期化が必要 new
u := new(user)
u.name = "taguchi"
u.score = 20
fmt.Println(u) // 初期値 &{"", 0}

// 初期値を設定
u := user{"taguchi", 50}
    or
u := user{name:"taguchi", score:50}

メソッド(データ型に紐付いた関数)

type user struct {
    name string   // フィールド
    score int
}

func (u user) show() { // レシーバ 値渡し(uでフィールドにアクセスできる)
    fmt.Printf("name:%s, score:%d\n", u.name, u.score)
}

func (u *user) show() { // 参照渡し
    fmt.Printf("name:%s, score:%d\n", u.name, u.score)
}

u.show()

インターフェイス
メソッドの一覧を定義したデータ型
異なる構造体でも同じインターフェイスを満たす型として処理できる


type greeter interface {
    greet() // 挨拶
}

type jananese struct { }
type american struct { }

func (j japanese) greet() {
    fmt.Println("Konnichiwa!")
}

func (a american) greet() {
    fmt.Println("Hello!")
}

func main() {
    greeters := []greeter{japanese{}, american{}} // インターフェイスを満たしている

    for _, greeter := range greeters {
        greeter.greet()  //  Konnichiwa! -> Hello!
    }
}

空のインターフェイス型
すべてのデータ型が空のインターフェイスを満たしている

// 空のインターフェイスをつかってあらゆる型を受け取る
function show(t interfae{}){
    // 2種類の型判断

    // 型アサーション
    _, ok := t.(japanese)
    if (ok) {
        fmt.Println("I am japanese")
    } else {
        fmt.Println("I am not japanese")
    }

    // 型Swich
    switch t.(type) {
    case japanese:
        fmt.Println("I am japanese")
    default:
        fmt.Println("I am not japanese")
    }
}


func main() {
    greeters := []greeter{japanese{}, american{}} // インターフェイスを満たしている

    for _, greeter := range greeters {
        greeter.greet() //  Konnichiwa! -> Hello!
        show(greeter) //  "I am japanese" -> "I am not japanese"
    }
}

goroutine goルーチン:並行処理

package main

import (
    "fmt"
    "time"
)

func task1() {
    time.Sleep(time.Secound * 2)
    fmt.Println("task1 finished!")
}

func task2() {
    fmt.Println("task2 finished!")
}

// 何も起きない goルーチンが終わる前にmainが終わっているので
func main() {
    go task1() // go をつける
    go task2()
}

func main() {
    go task1() // go をつける
    go task2()
    
    time.Sleep(time.Secound * 3) // 3秒待つ
}

チャンネル
データの受け渡しをするパイプ
goルーチンではreturnは使えない

func task1(result chan string) {
    time.Sleep(time.Secound * 2)
    result<- "task1 finished!"    // <- チェネルにデータを入れる
}

func task2() {
    fmt.Println("task2 finished!")
}

func main() {
    result := make(chan string) // チャネル型 chan string
    go task1(result)
    go task2()

    fmt.Println(<-result) // resultに何か入るまで処理を待つ
}

Webサーバを作成

パッケージ
http://golang.org/pkg/

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi %s !", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}