snippet: go (match, 配列、乱数、ループ、キー入力、別ファイルに分ける)

## http

### POST値の取得

```go
func tweet(w http.ResponseWriter, r *http.Request) {
  e := r.ParseForm()
  text := r.Form.Get("text")
  fmt.Println(text)
}
```

```go
// 以下3つとも同じ
r.Form.Get("text")
r.FormValue("text")
r.PostFormValue("text")
```

```sh:curlでpostの例
curl -X POST -d "text=test1" http://localhost:5937/tweet
```

## 文字列

### Sprintf等

* Printlnはフォーマットを指定できない。改行がつく。
* Printfはフォーマットを指定できる。
* Sprintfは標準出力しない。

```go:sprintf.go
package main

import (
        "fmt"
        "time"
)
func main() {
        now := time.Now()
        fmt.Printf("%04d-%02d-%02d",now.Year(), now.Month(), now.Day())
}
```

### match

* [regexp パッケージ - golang.jp](http://golang.jp/pkg/regexp)

```go:match.go
package main

import (
        "fmt"
        "regexp"
)

func main() {
        var message string
        message = "これは日本語です"

        // match
        re := regexp.MustCompile(`日(本)語`)
        if re.MatchString(message) {
                str := re.ReplaceAllString(message, "$1")
                fmt.Println(str) //これは本です

                str = re.FindString(message)
                fmt.Println(str) //日本語
        } else {
                fmt.Println("なし")
        }
}
```

----

## ファイル操作

### ファイル書き込み

```go:write.go
package main

import (
	"io/ioutil"
	"os"
)

func main() {
	content := []byte("hello world\n")
	// 共有フォルダ に書き込む場合
	ioutil.WriteFile("\\\\192.168.100.1\\share\\b.log", content, os.ModePerm)
	// c:\temp\a.log に書き込む場合
	ioutil.WriteFile("c:\\temp\\a.log", content, os.ModePerm)
}
```

```go:エラーチェック(ver1.7.4)
package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	fwrite("a.txt", []byte("hello world\n"))
	fwrite("/a/a.txt", []byte("hello world\n"))
}

func fwrite(filepath string, content []byte) {
	err := ioutil.WriteFile(filepath, content, os.ModePerm)
	if err != nil {
		fmt.Println("書き込み失敗: " + filepath)
	} else {
		fmt.Println("書き込み成功: " + filepath)
	}
}
```

### ファイル権限

```go:
os.Chmod("a.txt", 0600)
```

### ファイル読み込み

```go:read.go
package main

import (
	"fmt"
	"io/ioutil"
	//"os"
)

func main() {
	fread("a.txt")
}

func fread(filepath string) {
	res, err := ioutil.ReadFile(filepath)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println(string(res))
	}
}
```

## 構文

### 配列

```go:配列
package main
import "fmt"

func main() {
        var motion string
        actions := []string{" ", "p", "k", "<", ">"}
        motion = actions[2]
        fmt.Println(motion) //k
}
```

### 連想配列

```go:連想配列
actions := map[string]string{" ": " ", "p": "p", "k": "k", "<": "<", ">": ">"}
```

### 乱数

```go:ランダム
import (
	"math/rand"
	"time"
)
...
rand.Seed(time.Now().UnixNano())
motion = actions[rand.Intn(5)]
```

### 繰り返し

```go:繰り返し
for i:=0; i<x; i++ {
	space += " "
}
```

### 永久ループ

```go:永久ループ
for {
}
```

### キー入力

```go:
func keydown() string {
	var k string
	fmt.Scan(&k)
	return k
}

actions := map[string]string{" ": " ", "p": "p", "k": "k", "<": "<", ">": ">"}
var key string
key = keydown()
motion = actions[key]
```

----

## 別ファイルに分ける

### 別ファイルに分ける (別package名)

* 1文字目が大文字だと他から呼べる

```go:act/act.go
package act

func x_space(x int) string {
	var space string
	for i:=0; i<x; i++ {
		space += " "
	}
	return space
}

func P(x int) string {
	var figure string
	figure += x_space(x) + " x " + "\n"
	figure += x_space(x) + " xxxxx" + "\n"
	figure += x_space(x) + " x " + "\n"
	figure += x_space(x) + "x x"
	return figure
}
```

```go:a.go
import (
	"./act"
)
...
motion = act.P(x)
```


### 別ファイルに分ける (同じpackage名)

* [GoでJSON APIを書く - sgykfjsm.github.com](http://sgykfjsm.github.io/blog/2016/03/13/golang-json-api-tutorial/)

```go:todo.go
package main

import "time"

type Todo struct {
	Name      string    `json:"name"`
	Completed bool      `json:"completed"`
	Due       time.Time `json:"due"`
}

type Todos []Todo
```

```go:main.go
package main

import (
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

func main() {
	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/todos", TodoIndex)
	router.GET("/todos/:todoId", TodoShow)

	log.Fatal(http.ListenAndServe(":8080", router))
}
```

```go:handler.go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "Welcome!")
}

func TodoIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	todos := Todos{
		Todo{Name: "Write presentation"},
		Todo{Name: "Host meetup"},
	}

	// utf-8
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)

	if err := json.NewEncoder(w).Encode(todos); err != nil {
		panic(err)
	}
}

func TodoShow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	fmt.Fprintf(w, "Todo show: %s", ps.ByName("todoId"))
}
```

```sh:実行
go run *.go
もしくは
go build
```

## DB

### mysql-client

* [go-sql-driver/mysql: Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package](https://github.com/go-sql-driver/mysql)

```
go get github.com/go-sql-driver/mysql
```

(go getしたものは `$GOPATH/src/github.com/go-sql-driver/mysql/` に入っている。)

```mysql:rootアカウントのパスワード設定例
GRANT SELECT ON *.* TO root@localhost IDENTIFIED BY "root";
FLUSH PRIVILEGES;
```

```go:mysql
package main

import (
	"database/sql"
	//"fmt"
	//_ "github.com/yuuki/go-sql-driver-mysql"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "root:root@/test")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()
	db.Query("select now()")
}
```

-----

## 通信

* [Golang: HTTP リクエストを送信する - Sarabande.jp](http://blog.sarabande.jp/post/90736041568)

### 受け側の準備

```php:a.php
<?php
var_dump($_POST);
```

```sh:8000番でlisten
php -S 0.0.0.0:8000
```

### GET

```sh:get1.go
package main

import (
	"io/ioutil"
	"net/http"
)

func main() {

	response, _ := http.Get("http://localhost:8000/a.php")
	body, _ := ioutil.ReadAll(response.Body)
	defer response.Body.Close()

	println(string(body))

}
```

```sh:エラー例)8000番でlistenされていない場合
$ go run get1.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x48 pc=0x5eb949]

goroutine 1 [running]:
main.main()
	/home/user1/get1.go:16 +0x139
exit status 2
```

### POST1

```go:post1.go
package main

import (
	"io/ioutil"
	"net/http"
	"net/url"
)

func main() {

	resp, _ := http.PostForm(
		"http://localhost:8000/a.php",
		url.Values{"foo": {"bar"}},
	)

	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	println(string(body))
}
```

```sh:結果
$ go run post1.go
array(1) {
  ["foo"]=>
  string(3) "bar"
}
```

### POST 2

```go:post2.go
package main

import (
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

func main() {

	client := &http.Client{}
	data := url.Values{"foo": {"bar"}}

	resp, _ := client.Post(
		"http://localhost:8000/a.php",
		"application/x-www-form-urlencoded",
		strings.NewReader(data.Encode()),
	)
	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	println(string(body))
}
```

```sh:結果(先ほどと同じ)
$ go run post1.go
array(1) {
  ["foo"]=>
  string(3) "bar"
}
```

### redirect

```go
http.Redirect(w, r, "/todos", 303)
```

```go:urlも可能
http.Redirect(w, r, "https://www.yahoo.co.jp/", 303)
```