今年の GWは javascript / golang / objective-c を書いています。まだまだ初心者ですが Golangを勉強した備忘録です。内容は以下です。
- 標準パッケージを使ってみた感じ (os/exec, reflect, net/http)
- 自作パッケージを作ってテストしてみた感じ
go version 1.2.1です。
Package os/exec
Goプログラムからのシェルコマンドの実行, C言語でいう system()とか exec()の機能を提供します。
下記例では, vmstat出力先の stdoutを bytes.Buffer型に紐づけるようにしています。
cmd := exec.Command("vmstat")
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
}
その後は文字列操作のstringsや文字変換のstrconvという便利なパッケージを使って料理します。
例えば,line, err := out.ReadString(‘\n’)で行を取得して,strings.Split(line, ” “)で部分文字列に分割して配列にいれたりという事が簡単にできて, c言語より圧倒的に楽でいい感じです。
Package reflect
reflectパッケージは型を取りだす機能を提供します。
変数に値を設定したり,関数に渡したinterface{}から静的な型情報を取得したりやjsonと構造体の相互変換ができるようです、
以下ではValueOf()でreflect.Value型にして,Kind()で型情報を取得しています。
package main
import (
"fmt"
"reflect"
)
func match(a, b interface{}) bool {
aval := reflect.ValueOf(a) // Value Data
if aval.Kind() != reflect.Ptr { // Type Data
return false
}
bval := reflect.ValueOf(b)
if aval.Elem().Kind() != bval.Kind() {
return false
}
return true
}
func main() {
var i int
var j float32
var k string
t1 := match(&i, 24)
fmt.Println("t1 : ",t1)
t2 := match(&j, 15.4)
fmt.Println("t2 : ",t2)
t3 := match(k, "abc")
fmt.Println("t3 : ",t3)
}
結果は以下になります。
$ go run reflect_example.go
t1 : true # intとint
t2 : false # float32とfloat64
t3 : false # Ptrでない
reflect.MakeFuncを使うと、動的に関数を作ることができるようです。
Package net/http
続いて, net/httpのhttp-client機能を試してみました。
res, err := http.Get("[api-url]")
if err != nil {
fmt.Println(fmt.Println(err))
}
fmt.Println("http-header : ", res)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(fmt.Println(err))
}
str := byteToString(body[:])
fmt.Println("http-body : ", str)
GET / POST も楽でいい感じです。
最近のLLはJITコンパイラの恩恵もありけっこう速いみたいだけど,コンパイラ言語なのでより速いことを期待。
goroutine / Channel
Go言語ではMessage-passing communicationというアプローチの並行処理プログラミングをサポートしています。
Channel で goroutine 間でのメッセージパッシングを試しました。
func rcvCannel(_ch chan bool) {
/* reciever */
for done := range _ch {
fmt.Println(time.Now(), " : ", done)
}
}
func main() {
/* make channel*/
ch := make(chan bool)
go rcvCannel(ch)
done := false
for i := 0; !done; i++ {
if i == 5 {
done = true
}
/* sender*/
ch <- done
time.Sleep(time.Second * 1)
}
fmt.Println("done!")
}
自作パッケージ
klogという自作Loggerパッケージを例にします。
package main でなく package [自作パッケージ名] に変えます。
正しい手順ではないと思いますが,以下のディレクトリ構成にしました。
サブディレクトリに自作パッケージを置きます。
.
├── CHANGELOG.md
├── README.md
├── klog
│ └── klog.go
└── klog_test.go
Package testing
パッケージのテストはtestingを使います。
例えば, 自作したklogパッケージ内の func Printlog(func_n string) bool をテストしたい場合, func Test*** (t *testing.T)の *** にテストターゲットの関数名を入れます。
package klog
import (
"testing"
"./klog"
)
func TestPrintlog(t *testing.T) {
/* expected TRUE test */
actual := klog.Printlog("test")
expected := true
if actual != expected {
t.Errorf("got %v\nwant %v", actual, expected)
}
}
go run で実行しようとすると go run: cannot run *_test.go files と怒られるようにsuffixが_testのファイルはrunできません。
go test で実行します。
$ go test klog_test.go
ok command-line-arguments 0.026s
ベンチマークを取る場合は, func Benchmarkxxxと書いて -benchオプションを指定します。
$ go test -bench klog_test.go
色々いじった後は以下で整形するといい感じです。
$ gofmt -w xxx.go
# recursive
$ find . -name '*.go' -exec gofmt -w {} \;
Reference
effective_goの翻訳サイトは若干情報が古い気がしています。FAQ - golang.jp をまず目を通しておくと良いと思います。
標準パッケージの情報を見る事が多いですが、最近の情報に関しては GoogleGroup や Gocon, Gokenの活動を見ています。
以下, Golangで書かれたプログラムです。勉強になります。
- docker (Linuxコンテナ)
- martini (WEBフレームワーク)
- negroni (WEBフレームワーク)
- pt (高速検索ツール like ack,ag)
- heka
- gocircuit
- go oracle (静的解析ツール)
* この記事はkarota-projectの活動に関する記事です。