▶ 技術めも
golang memo
パッケージ
http://golang.jp/pkg
JSON
package main
import (
"fmt"
"encoding/json"
)
type Person struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"-"`
Age int `json:"age"`
Adress string `json:"adress,omitempty"`
memo string
}
func main() {
// 構造体 to JSON
person := &Person{
1,
"Gopher",
"tatenosystem@gmail.com",
5,
"",
"golang",
}
b, _ := json.Marshal(person)
fmt.Println(string(b)) // []byte -> string
// JSON to 構造体
var person2 Person
b2 := []byte(`{"id":1, "name":"Gopher", "age":5}`)
json.Unmarshal(b2, &person2)
fmt.Println(person2)
}
ポインタ
package main
import (
"fmt"
)
func callByValue(i int) {
i = 20;
}
// p *int:番地 -> *pi 実体
func callByRef(pi *int) {
*pi = 30;
}
func main() {
i := 10
callByValue(i)
fmt.Println(i)
callByRef(&i) // i 実体 -> &i 番地
fmt.Println(i)
}
// ポインタ * で実体にアクセス
// 実体 & で番地に変換
ファイル
package main
import (
"fmt"
"log"
"os"
)
func writeTest() {
file, err := os.Create("./f.txt");
if err != nil {
log.Fatal(err)
}
defer file.Close()
msg := []byte("Hello Word !\n")
_, err = file.Write(msg) // 書き込まれたバイト数, err
// _, err = file.WriteString("Hello tatenosystem :)\n")
// _, err = fmt.Fprintf(file, "Hello (^^)/\n")
if err != nil {
log.Fatal(err)
}
}
func readTest() {
file, err := os.Open("./f.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// スライスの用意
msg := make([]byte, 12)
_, err = file.Read(msg) // スライスの上限までしか取得できない
if err != nil {
log.Fatal(err)
}
fmt.Println(string(msg)) // []byte -> string
}
func main() {
writeTest()
readTest()
}
JSONファイル読み書き
package main
import (
"fmt"
"encoding/json"
"log"
"os"
)
type Person struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"-"`
Age int `json:"age"`
Adress string `json:"adress,omitempty"`
memo string
}
func encodeTest() {
// 構造体 to JSON
person := &Person{
1,
"Gopher",
"tatenosystem@gmail.com",
5,
"",
"golang",
}
file, err := os.Create("./p.json")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// エンコーダ取得
encode := json.NewEncoder(file)
// JSONエンコードしたデータの書き込み
err = encode.Encode(person)
if err != nil {
log.Fatal(err)
}
}
func decodeTest() {
file, err := os.Open("./p.json")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// データを書き込む構造体
var person Person
// デコーダ取得
decoder := json.NewDecoder(file)
// JSONデコードしたデータの読み込み
err = decoder.Decode(&person)
if err != nil {
log.Fatal(err)
}
fmt.Println(person)
}
func main() {
encodeTest()
decodeTest()
}
io/ioutil パッケージ
package main
import (
"fmt"
"log"
_ "os"
"io/ioutil"
"reflect"
)
func writeTest() {
msg := []byte("HogeFuga Hello :) !!!\n")
err := ioutil.WriteFile("./f.txt", msg, 0666)
if err != nil {
log.Fatal(err)
}
}
func readTest() {
// file, _ := os.Open("./f.txt")
// msg, err := ioutil.ReadAll(file) // サイズを気にしなくていい
msg, err := ioutil.ReadFile("./f.txt") // サイズを気にしなくていい
if err != nil {
log.Fatal(err)
}
fmt.Println(reflect.TypeOf(msg)) // []uint8
fmt.Println(string(msg)) // []byte -> string
}
func main() {
readTest()
writeTest()
}
net/http パッケージ
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)
}
POST で JSON を受け取ってファイル保存
curl http://localhost:8080/person -d '{"id":1, "name":"tatenosystem"}'
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
)
type Person struct {
ID int `json:id`
Name string `json:name`
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello %s !", r.URL.Path[1:])
}
func PersionHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() // 処理の最後にBodyを閉じる
if r.Method == "POST" {
fmt.Println("POST")
var person Person
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&person) // errが初めて出てくる
if err != nil {
log.Fatal(err)
}
// ファイル保存 {id}.txt
filename := fmt.Sprintf("%d.txt", person.ID)
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// ファイルにNameを書き込む
_, err = file.WriteString(person.Name)
if err != nil {
log.Fatal(err)
}
// レスポンスとしてステータスコード201
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, "%s OK!", person.Name)
}
}
func main() {
http.HandleFunc("/", IndexHandler)
http.HandleFunc("/person", PersionHandler)
http.ListenAndServe(":8080", nil)
}
html/template パッケージ
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"io/ioutil"
"os"
"html/template"
"strconv"
)
type Person struct {
ID int `json:id`
Name string `json:name`
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello %s !", r.URL.Path[1:])
}
var t = template.Must(template.ParseFiles("index.html"))
func PersionHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() // 処理の最後にBodyを閉じる
// t, err := template.ParseFiles("index.html")
// if err != nil {
// log.Fatal(err)
// }
if r.Method == "POST" {
fmt.Println("POST")
var person Person
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&person) // errが初めて出てくる
if err != nil {
log.Fatal(err)
}
// ファイル保存 {id}.txt
filename := fmt.Sprintf("%d.txt", person.ID)
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// ファイルにNameを書き込む
_, err = file.WriteString(person.Name)
if err != nil {
log.Fatal(err)
}
// レスポンスとしてステータスコード201
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, "%s OK!", person.Name)
} else if r.Method == "GET" {
// パラメータ取得
id, err := strconv.Atoi(r.URL.Query().Get("id"))
if err != nil {
fmt.Println("ERROR strconv")
log.Fatal(err)
}
filename := fmt.Sprintf("%d.txt", id)
b, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
// person作成
person := Person{
ID: id,
Name: string(b),
}
// レスポンス
t.Execute(w, person)
}
}
func main() {
http.HandleFunc("/", IndexHandler)
http.HandleFunc("/person", PersionHandler)
http.ListenAndServe(":8080", nil)
}
index.html
Jinja2 ライクな記述
<html>
<head>
<title>person</title>
</head>
<body>
<h1>{{ .ID }} : {{ .Name }}</h1>
</body>
</html>
ゴールーチン
直列処理
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env",
}
for _, url := range urls {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
fmt.Println(url, res.Status)
// body 表示
byteArray, _ := ioutil.ReadAll(res.Body) // read.Body は IO I/F
fmt.Printf(string(byteArray))
}
}
並行処理
package main
import (
"fmt"
"io/ioutil"
"log"
"time"
"net/http"
)
func run(url string) {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
fmt.Println(url, res.Status)
// body 表示
byteArray, _ := ioutil.ReadAll(res.Body) // read.Body は IO I/F
fmt.Printf(string(byteArray))
}
func main() {
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env",
}
for _, url := range urls {
go run(url)
}
// main() が終わらないように待つ
time.Sleep(time.Second * 3)
}
sync.WaitGroup でインクリメント/デクリメント
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"sync"
)
func run(url string, wait *sync.WaitGroup) {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
fmt.Println(url, res.Status)
// body 表示
byteArray, _ := ioutil.ReadAll(res.Body) // read.Body は IO I/F
fmt.Printf(string(byteArray))
wait.Done() // デクリメント
}
func main() {
wait := new(sync.WaitGroup)
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env",
}
for _, url := range urls {
wait.Add(1) // インクリメント
go run(url, wait)
}
// wait が 0 になるまで待つ
wait.Wait()
}
チャンネルで結果を取得
package main
import (
"fmt"
"log"
"net/http"
)
func run(url string, statusChan chan string) {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
fmt.Println(url, res.Status)
statusChan <- res.Status
}
func main() {
statusChan := make(chan string) // チャンネル作成
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env",
}
for _, url := range urls {
go run(url, statusChan)
}
for i := 0; i < len(urls); i++ {
fmt.Println(<- statusChan)
}
}
関数の返り値が(呼び出し専用)チャンネル
package main
import (
"fmt"
"log"
"net/http"
)
// 戻り値が chan string( <- で呼び出し専用。main で書き込めない )
func runAll(urls []string) <- chan string {
statusChan := make(chan string) // チャンネル作成
for _, url := range urls {
go func(url string) {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
statusChan <- url+" - "+res.Status
}(url)
}
return statusChan
}
func main() {
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env",
}
statusChan := runAll(urls)
for i := 0; i < len(urls); i++ {
fmt.Println(<- statusChan)
}
}
チャンネルを select で待つ(タイムアウトチャンネル)
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// 戻り値が chan string( <- で呼び出し専用。main で書き込めない )
func runAll(urls []string) <- chan string {
statusChan := make(chan string) // チャンネル作成
for _, url := range urls {
go func(url string) {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("%t", res.Body)
defer res.Body.Close()
statusChan <- url+" - "+res.Status
}(url)
}
return statusChan
}
func main() {
// 2秒後に値が取り出せるチャンネル
timeout := time.After(time.Second * 2)
urls := []string{
"http://tatenosystem.com",
"http://codegame.tatenosystem.com",
"http://tatenosystem.com/env/wait/",
}
statusChan := runAll(urls)
LOOP_FOR: // ラベル
for { // break するまで抜けられないので、2秒待ってしまう
select {
case status := <-statusChan:
fmt.Println(status)
case <-timeout:
fmt.Println("TIMEOUT")
break LOOP_FOR // ラベル指定でbreak
}
}
fmt.Println("END")
}
バッファ付きチャンネル
package main
import (
"fmt"
"time"
)
func main() {
// チャンネルバッファ 5
ch := make(chan int, 5)
// チャンネル書き込み
go func() {
for i := 0; i < 10; i++ {
fmt.Println("Writing", i)
ch <- i
}
// ch <- -1 // 停止信号
close(ch) // チャンネルを閉じる
}()
time.Sleep(time.Second * 2)
// チャンネル読み込み
for {
v, ok := <-ch
if !ok {
break
}
// if v == -1 { break }
fmt.Println("Read", v)
}
}
Mutexロック
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.RWMutex
// gorutine
for i := 1; i <= 5; i++ {
go func(){
for i := 0; i < 5; i++ {
mu.RLock()
fmt.Printf("Reader %d Acquired lock\n", i)
time.Sleep(time.Second)
mu.RUnlock()
}
}()
}
// 3秒後にロック
time.AfterFunc(3 * time.Second, func(){
fmt.Println("LOCK")
mu.Lock()
})
// 6秒後にアンロック
time.AfterFunc(6 * time.Second, func(){
fmt.Println("UNLOCK")
mu.Unlock()
})
// 止めておかないと main が終了してしまう
time.Sleep(time.Second * 9)
}
その他
引数
package main
import (
"fmt"
"os"
)
func main() {
name := os.Args[1]
s, _ := os.Stat(name) // ファイル取得
// go run args1.go p.json
// p.json: 33
fmt.Printf("%s: %d\n", name, s.Size()) // ファイルサイズ数
}
外部プログラム実行
package main
import (
"fmt"
"os/exec"
"log"
)
func main() {
out, err := exec.Command("uname", "-a").Output()
if err != nil { log.Fatal(err) }
fmt.Printf(string(out))
}
5秒ごとに通知されるチャンネル作成
package main
import (
"fmt"
"time"
)
func main() {
// 5秒ごとに通知されるチャンネル作成
ch := time.Tick(time.Second * 5)
for i := 0; i < 10; i++ {
t := <-ch
fmt.Println(t)
}
}