Showing posts with label golang. Show all posts
Showing posts with label golang. Show all posts

Thursday, July 14, 2011

Google App Engine for Goをインストール

2009年11月ごろにお披露目されましたGo言語で2010年初頭に遊んだ経験がありました。
2011年5月に、やっとGoogle App Engineのサポート言語第3号としてGo言語が登場しました。
(第一がPython, 第二がJava)
これは、あまりぱっとした適用分野が見つかっていなかったGo言語陣営にとって期待の星のようです。

早速Google App EngineのGも知らない私が、Go言語を1Kステップくらい書いたことがあるレベルで取り組んでみます。

1.まず、Go言語開発環境を作り直しです(笑)
Goのランタイムエンジンはだいぶ頻繁に改良を重ねております。
2011年7月現在r58.1という数字がついており、そんなメジャーバージョン番号あるのか?と突っ込みたくなるだけでなく、
本当にいろいろ改良されており、Makefileやら周りのツールも全く互換性がありません。
2010年に私が作った環境からはだいぶ差分が蓄積しているようでした。
(primitivesのひとつ、floatもないのかよ、というレベル)
そこで、開発環境をまっさらから作り直します。
下記資料を参照します。
http://golang.org/doc/install.html#tmp_17

1.1開発環境最新版ソースをダウンロード。
まず、googlecodeにあるGo言語開発環境の最新版をインストールします。
このためには、hg(mercurial)パッケージが必要です。
私の使っているFedora 14では、yum install hgと打つといろいろ依存性が解決されてhgがインストールされました。
ubuntu系ではapt-get install mercurialとなるでしょうか。
問題ないなら、下記を打ってみましょう。
hg clone -r release http://go.googlecode.com/hg/ <自分のGo用ディレクトリのパス>
hgパッケージがgooglecodeから開発環境最新版ソースをダウンロードしてくれます。
このディレクトリパスが、これからの作業場所になります。

1.2開発環境バイナリを自動生成。
ディレクトリ内のsrc/all.bashを叩くとバイナリは自動生成されます。
ただダウンロードしただけではsrc/all.bashは動いてくれません。
ちゃんと上の資料に書いてあるとおり、gawkやedをインストールすれば、ちゃんと動いてくれます。
all.bashが動けば、Go言語で書いたスクリプトをコンパイルするためのバイナリファイルが生成されます。
もしできなかった場合は、上記必要パッケージが入っていないか、Go専用環境変数($GOROOT, $GOARCH, $GOOS)が正しいか、
確認して下さい。おそらく、64bitなのに386と指定しているなどではないでしょうか。

2.Google App Engine用のSDKをダウンロードする。
Google App Engineでは、PythonやJavaやGoで書いたプログラムをGoogleにアップロードして、
サービスを動かします。
やるべきことは、プログラムを書くこととアップロードすることです。
プログラムを書くのを助けるのは、プログラムのテスト環境です。
アップロードを助けるのは、アップローダですね。
これらを提供するのがGAE SDKです。
いずれもpythonランタイム上で動くプログラムで書かれているので、
「私はGo言語だけをやりたい」という人でも、Pythonランタイムを入れておけばテストが簡単になったり嬉しいことがあります。
私はFedoraにyum install pythonして上記Pythonランタイムを用意しました。
本命のSDKは下記からダウンロードします。
http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Go
zipファイルなので好きなところに展開します。私はユーザディレクトリの直下。
よく使うコマンドが入っているので、パスを通してあげます。
私のFedoraでは、.bash_profile末尾に下記を追記して、最後にコマンドをうちます。
【追記】
export PATH=/***さっき展開したところ***/:$PATH
【コマンド】
source .bash_profile

下記資料も参照しました。
http://d.hatena.ne.jp/ma_chupic_chu/20110623/1308813211

3.helloworldを動かしてみる。
まずはHelloworldの詳細が書いてあるドキュメントをダウンロードします。
http://code.google.com/appengine/downloads.html
zipですので好きなところに展開し、index.htmlを開きます。
hello worldという章がありますので、ここに書いてある通りに、2つのディレクトリと2つのファイルを作ります。
myapp/
app.yaml
hello/
hello.go
hello.goの中身は下記のような感じです。
package hello

import (
    "fmt"
    "http"
)

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, world!")
}
私は匿名関数を何かと使いたがるので、下記のように書き換えてしまいます。

package hello

import (
    "fmt"
    "http"
)

func init() {
        http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) () {
                fmt.Fprint(w, "Hello, world!")
        })
}

myappディレクトリの上位に移動して、dev_appserver.py myappと打ちますと、テストが実行されます。
テストでは、自作プログラムが簡易webサーバ上で動くので、ブラウザからサーバにアクセスすると結果が得られます。
テストが実行されている最中に、ブラウザからlocalhost:8080を起動しますと、下記のような結果が得られました。

いかがでしょう。Goランタイムはもしかするとおまけかもしれませんが、開発環境として漏れのない環境を作ってみました。

Friday, November 19, 2010

golangのsliceコピー

goパッケージのアップデートがどうやら激しいようで、
hg updateかけないと仕様のページ書いてあることも実行でないようです。

今日は、goパッケージのアップデートにより使用可能となりました、
copy(dst, src []T)についてご説明。

go言語の「スライス」がもっと便利になればいいのに!
そう思っていた人も多いはず。

そこで、まずappendが使用可能になりました!
これで使用頻度は5割増しだ。

文法は
append(アペンドされるスライス, アペンドするオブジェクト)でございます。

var a []int{0,1,2}
b := append(a, 3)
// b == []int{0, 1, 2, 3}

次にcopyが可能になりました。
早速スライスをコピーして別のスライスを用意していじって見ましょう。
文法は
copy(コピー先スライス, コピー元スライス)でございます。

【まずは失敗作1】
var a []int{0,1,2}
b := a
edit(a); output(a); output(b)

ぉ、スライスはポインタであるらしいことを忘れていました!
だから、ポインタをコピーしても、元のaとbは同じものを参照しているのです。

【次に失敗作2】
var a []int{0, 1, 2}
b := a
copy(a, b)
edit(a); output(a); output(b)

もちろんこれでもだめ。
bはただのaのコピーロボット。
aの実体が編集されればbも編集されているということ。

【成功例】
var a []int{0, 1, 2}
b := make([]int(len(a))
copy(b, a)
edit(a); output(a); output(b)


これでaとbは違う実体を持つことができる。
これでこそコピー

Saturday, November 06, 2010

[Go]パッケージを作る

Goにおいて、「パッケージ=外部のgoソースファイルから参照できる関数や構造体などの集合」です。

関数をパッケージにする、つまり関数を外部から参照させるには、
下記の作業をします。

1.ファイル先頭に"package <パッケージ名>"を挿入。
 (package mainと書いてある既存ソースなら、mainを<パッケージ名>に置換)
2.関数の名前の先頭を大文字にする。

これだけです。

既存ソースからの改変を例にすると、
既存ソースが下記であれば

package main

func test() {
//これをパッケージ化
return
}

パッケージ化するとこのようになります。

package test

func Test() {
//これをパッケージ化
return
}


これを外部ファイルから参照するときは

1.import <パッケージ名>を追加
2.<パッケージ名>.<関数名>で参照

以上です。簡単です。

Sunday, February 07, 2010

goroutine強制終了

最近goにはまっています。
チャンネルという新しい同期、非同期通信の仕組みや関数の複数値返し、
待ってたものがやっときたという感じです。

ずんWiki - golang/逆引き/goroutineを終了するには

goで遊んでいてわからなくなったポイントがありました。
go func()で簡単に走らせることができるgoのスレッド、goroutine。
自分のスレッドを強制的に終わらせるために用意された、グローバルな関数がありました。
runtime.Goexit()
上記を参照しました。

下記のようなときに使えます。

例:チャンネルを使ってgoroutineが終わるのを待ちますが、
  強制終了されちゃうとチャンネル受信ができないので終われません。
  ひたすら待ち続けてプロセスが死んじゃいます、という例:


package main
import (
"fmt";
"runtime"
)
var ch= make(chan int, 1);
func main() {
go func() {
func() {
fmt.Printf("Stop goroutine1\n");
runtime.Goexit();
}();
ch <- 1;
}();
<-ch;
}



出力:エラー吐いてプロセス死亡・・・


package main
import (
"fmt";
// "runtime"
)
var ch= make(chan int, 1);
func main() {
go func() {
func() {
fmt.Printf("Stop goroutine1\n");
// runtime.Goexit();
}();
ch <- 1;
}();
<-ch;
}


出力:Stop goroutine1