Looks Go To Me

golang をゆったり学びます。

golang append で、3つ以上のスライスを連結したい

golang の場合、2つのスライスを連結して1つにするには

package main

import "fmt"

func main() {
    a := []byte("hoge")
    b := []byte("hage")
    c := append(a, b...)
    fmt.Println(string(c))
}

このようにする。では、3つは?

package main

import "fmt"

func main() {
    a := []byte("hoge")
    b := []byte("hage")
    c := []byte("var")
    d := append(a, b..., c...)
    fmt.Println(string(d))
}

これはエラー。残念!!

正解は

package main

import "fmt"

func main() {
    a := []byte("hoge")
    b := []byte("hage")
    c := []byte("var")
    d := append(a, append(b, c...)...)
    fmt.Println(string(d))
}

こうなんですねぇー。これはちょっとめんどいね。

なので、こんな関数はどうかなって思ったんだけど

func appendMultipleByteSlices(bSlices ...[]byte) []byte {
    i := 0
    for _, b := range bSlices {
        i = i + len(b)
    }
    capped := make([]byte, 0, i)
    for _, b := range bSlices {
        capped = append(capped, b...)
    }

    return capped
}

わざわざこんなの造らなくてもできそうだなぁ、感があるんだよねぇ。

誰かおしえてください。

別言語プロダクトの移植

revel 見ると言ってたが、ありゃ半分うそになった。すまん。

ということで、わけあって別言語プロダクトの移植をすることにしました。

その過程で思ったんですが

my $mar = "mar";
my $hoge = "$mar + $mar = $mar$mar";

みたいに文字列リテラル中に変数いれるのって go だとできないんですねぇ。

mar := "mar"
hoge := mar + "+" + mar + "=" + mar + mar

みたいにせんといかん。。。これは結構視認性と、記述時のミスを誘う感じ。こわい。

なんかいい方法ないかなぁ。

revel 読む(3)

さて、

github.com

ですが、main.go routes.go をつくったあとは、go build してます。

で、build してエラーになったとき、その原因が package get が足りてないからだろうと思われる場合、勝手に go get してもってきてくれて、また build するというループがある。素敵だな。

あ、で、なんか revel run hogehoge すると、9000 port は revel/harness/harness.go のなかで起動するリバースプロキシーが取って、アプリは開いてるポートを指定されて cmd.Run() されてるようだ。

watcher があってソースの改変などをみてリビルドするよう。

revel べんり!

次回はテストのとこみるか

revel 読む (2)

harness.Build 続き

tmp routes にあるソースがクリーンされ、もともとある main.go routes.go がなくなり const で埋め込んである MAIN, ROUTES テンプレをつかって新しい main.go routes.go がつくられる。 このテンプレは text/tempalte フォーマット。

main.go が作られる過程で RenderArgNames への引数などが、テンプレから変数名でアクセスできるようにプリプロセッシングされる。 が、ここめちゃくちゃムズいな。text/template が混ざってるせいもあるが、なにやってるかよくわかんない。

なにしろ Controller のぶんだけ RegisterController を呼ぶというソースをつくってるようだ。

ここはちょっとさらりと流そう。

revel 読む (1)

revel は いわゆる rails てきに scafold してもこっとテンプレを作ってくれる。

# revel new github.com/sheercat/anyweb

みたいに。

これの本体は

github.com

で、$GOPATH 以下に引数の名前でプロジェクトをつくり、conf とかもいきなり動く形で作成される。 ただし、main パッケージはなくて、まだ revel を通さずに実行はできない。

実行は

# revel run github.com/sheercat/anyweb

で、これの本体は

github.com

になってる。ここでは harness.Build() がよばれて tmp/main.go, routes/routes.go が生成される。ここが magic。

github.com

結構 go だと出来ない感じのことができるように動くのは、ここにプリプロセス的なものがあるからだろう。

revel new がつくる、.gitignore には tmp/ と routes/ が足されていて、このディレクトリ以下のファイルは動的につくられることが明確だ。

revel 読む (0)

Welcome to Revel, the Web Framework for Go!

を使うことに。選んだ理由としては、

  1. 「gin goji negroni など、軽量を必要に応じて使うか、net/http で十分だ」論が多すぎて、逆に「重量級のキャッチアップから逃げない勇気が必要なんじゃ?」って思ったから
  2. 軽量系を組み合わせるメリットはロックインされないことだが、context の扱いとか、ロックイン要素が多いので、もういっそみずからロックにインしたほうが「あー、これ、ロックインされるわーだめだー」みたいな精神状態を余裕で回避できそうだったから
  3. kocha, beego にくらべて極めて簡単なパフォーマンステストにおいて速かった
  4. kocha, beego よりも、複数の開発者が関わってるように見えた。
  5. martini とは迷ったが、ここはもはや好み

ということで。。。

go を効率よく書こうとするにつれ C に近づく

TL;DR
なし

mattn.kaoriya.net

とても参考になる記事です。

さて、この記事を見て、改めて golang を書きながら思っていることが明確になって来ました。タイトルのまんまですが

go を go らしく書こうとすると C で書くようなソースコードになる

ということです。ポインタの演算こそないですが go にはポインタの概念がありますし、実体渡しとポインタ渡しが明確に区別され、その際の値コピーのコストについても、C と同じようにコストがかかったりかからなかったりします。

append という便利関数はソースコードを短くし、見やすくしますが、効率は悪くなりますよね。5回とか 6回の append であれば append でいいんでしょうけど、たとえば、共通ライブラリのような、その append を使用している箇所がどれくらいの回数呼ばれるかわからない場面では、その append は make(...) + for ループで書きなおさざるを得ません。
append は、一発屋みたいなスクリプトを書きなぐる時の便利関数って感じなんだなって印象です。

何が言いたいかというと、go は LL じゃない。C でもない。あたらしいジャンルのプログラミング言語なんだなってことでした。

perl とか java も同じだろって言われそうですが、なんでしょう、go は印象てきには速度が速いLLみたいに登場したんだけど、日に日に C のほうへ近づいているというか、なんかそういう話です。
perl の場合は遅くても、「わかってるから」みたいな感じで使えるけど go で書いて遅いと、「それ go で書く意味ない」とかになるし、java の場合はそもそもそんな気軽に書きなぐる場面ないし、、、とか。

✧\\ g( 'ω' )o //✧