2011年8月6日土曜日

Update

あまりhgなど使わないので一応メモ
Go言語のインストール 最新リリースを保つ
にあるとおり
$ cd go/src
$ hg pull
$ hg update release
$ ./all.bash
で最新のソースを引っ張ってきてコンパイラとリンカ、
ライブラリがコンパイルされます。

とつぜんCGI

Google Go (golang) as CGI | The Roaming Coderを読んで Go でCGIをやってみた。
私がなにかやってみたというより、かいてあるとおりそのままやってみただけです。
1)まず、コード plain.go
    package main  
      
    import (  
      "os"  
    )  
      
    func main() {  
      os.Stdout.WriteString("Content-Type: text/plain;charset=us-ascii\n\n");  
      os.Stdout.WriteString("Hello world!\n\n");  
    }
2)これをコンパイル、リンクします
8g plain.go
8l -o plain.cgi plain.8
3) 以下の内容で.htaccess ファイルを作成します
Options +FollowSymLinks +ExecCGI
AddHandler cgi-script .cgi
これで、plain.cgiと.htaccessを同じディレクトリに置き、
localhostにブラウザからアクセスするだけです。
こんな状態で見えればひとまず成功です。

2010年2月27日土曜日

型について その3 len()とrange

goのチュートリアル、型についての続きです。

len()


goでは文字列、配列、map、スライス、チャネルの要素の数をlen()という関数で取得できるようです。

for i := 0; i < len(a); i++ { ... }
* UTF-8のときは一文字ずつになるのでしょうか。たぶんなるのでしょう。 組み込み関数と書かれていますが、実際はどうなっているのか不明です。 sizeof的組み込み関数なのでしょう。

len()実験

簡単に、lenの動きを見てみました。
package main

import (
"fmt"
)

func main() {
var a[16]uint;
fmt.Printf("len(a)=%d\n",len(a))
str := "12345678901234567890"
fmt.Printf("len(str)=%d\n",len(str))

}
結果は
$ ./8.out 
len(a)=16 
len(str)=40 
アレ? UTF8はバイト数ででてますね。 ということはこれsizeofと同じということのようです。 あと、文字列の最後にnullとかはあるのかもしれないけど入ってないと。

range

おそらくは、このlen()を内部でつかっているrangeという指定ができて
for i, v := range a { ... } 
こんな書き方でforeachになる、と。 foreach気持ち悪いけどfor i:=0;i< sizeof(a);i++ はオッケーという Cっぽい思想をよく汲んでいると思います。 今っぽい書き方をさせつつもアセンブラを意識できる記述なのかな。 よくできている。 しかし今時の人に受けるのかな。そこはわかりません。

rangeと文字列

rangeを文字列で使うサンプルを書いてみました。
package main

import (
"fmt"
)


func main() {
str := "12345678901234567890"
for v := range str {
fmt.Printf("%c\n",v)
}

}
こちらも普通にbyteで処理されちゃいますね。
$ ./8.out 














! 
" 
# 
$ 
% 
& 
' 

ひどいす。
まあきっとなにか、文字列用の関数とかあるのでしょう。

型について その2 配列とスライスとmap

配列


goでは配列の定義はこうします
var arrayOfInt [10]int;
これもまた、C言語のようにIntのポインタとして扱うことはできません。
しかし要素の入れ替えは自由にできます。


スライス


スライスは概念的にはDから持ってきたのでしょうか。
配列の一部だけを参照できるポインタです。
考え方的にはPythonなどにもあったような...よく覚えてません。

チュートリアルの解説はちょっとわかりにくいのですが
var a[10]int;
という配列があったときに
as := a[3:5];
とすると、asはa[3], a[4], a[5] を参照できる配列のスライスとなるようです。
例題欲しいなぁ。


C++的にこれも使いたいその場で生成可能で次に出てくる例題はこの、
その場で生成するタイプとなっています。
func sum(a []int) int {   // returns an int
s := 0;
for i := 0; i < len(a); i++ {
s += a[i]
}
return s
}
という配列を引数に持つ関数の実行の際に、 あらかじめ配列をべつに定義する必要は無くて、定義する場所で
s := sum(&[3]int{1,2,3})
としてスライスを生成して直接代入すると、 参照する側ではint s={1,2,3} が見えると。 ユーザー定義型でこれができたらかなりいろいろ楽になりそうです。 システムコール周りが天国になりそうな雰囲気。 スライスの生成で変数が使えるのでしょうか。たぶん、できるのでしょう。 やってみたいけど今は先に進みます。 スライスって言う呼び名は日本語的にイマイチだなぁ。 配列の部分参照みたいな言い方にするともっといまいちですがやや直感的と思います。

map

mapはrubyではおなじみのmap関数ではなく perlの方のmapのようです。 ここには説明が無いので不明ですが、ハッシュや連想配列にあたる物みたいです。
m := map[string]int{"one":1 , "two":2}
map関数はすごく便利なのできっとそれもあるのだろうと思います。
(知りませんが)

もうひとつ、チャネルという言葉が出てきますけど、
何の説明も無いので次いきます。
おそらくはstreamかsocktのことをいっているんじゃないかとおもいますが
わかりませんねー。

型について その1 String

チュートリアルの型についての説明は、いきなりハードルがあがります。
文字列、配列、ポインタ、スライス、mapなど
既存の概念を知らないとこの解説だけでついていくのは難しそうに思います。

String型


goの文字列型はバイト列ではなく固定の物で、
StringをbyteであつかったりIntのポインタに変換したりはできないそうです。
おそらくは文字列表現へのポインタで
単純にそれを入れ替える作りなのかなぁと今のところ考えています。
そのうちヘッダを読んでみます。


s := "hello"
if s[1] != 'e' { os.Exit(1) }
s = "good bye"
var p *string = &s
*p = "ciao"

こういう文字列の入れ替えは可能ですが

s[0] = 'x';
(*p)[1] = 'y';

文字列をポインタとして扱うことは不可能ですと。
文字列全体を入れ替えることはできるので
置換用の関数やらメソッドみたいなもので入れ替えろと言いたいのでしょう。

In C++ terms, Go strings are a bit like const strings, while pointers to strings are analogous to const string references.


これでわかるひととわからん人にわかれそうな解説...。
まあそういうことはとりあえず見なかったことにして先に進みましょう。

echoの作成

チュートリアルのEcho作成をやってみましたよ。
package main

import (
	"os"
	"flag" // command line option parser
)

var omitNewline = flag.Bool("n", false, "don't print final newline")

const (
	Space = " "
	Newline = "\n"
)

func main() {
	flag.Parse() // Scans the arg list and sets up flags
	var s string = ""
	for i := 0; i < flag.NArg(); i++ {
		if i > 0 {
			s += Space
		}
		s += flag.Arg(i)
		}
	if !*omitNewline {
		s += Newline
	}
	os.Stdout.WriteString(s)
}
NArgっていうのはどうやらArgvのことを言うようです。
このechoは引数を渡すとそれを標準出力に出すように見えます。

やってみましょう。
$ 8g echo.go
$ 8l echo.8
$ ./8.out
$
素で実行すると何もおこりません。
引数に文字列を渡してみましょう。
$ ./8.out echoのテスト
echoのテスト
$
そのままですね。

constキーワードについて解説がありますがこれはツッコミどころなし。
const 文字列 = 定義
で定数を定義できます。echoみたいに
const (
	Space = " "
	Newline = "\n"
)
もできるようです。

興味深いのはvar での変数定義方法です。
通常は
var s string = "";
としますが、""で括った物は文字列であることがコンパイラは知っているので
var s = "";
と書くこともできて、さらに明示的な定義&代入を
s := "";
とも書けるようにしました、と。

:=はmakefileみたいですね。

最後にセミコロンがついているのはおそらくC言語的に"" は連結できるから、なのでしょうか。
そのうちわかるでしょう。

flag.Boolの解説はここにはなさそうです。単にboolだと。三つ引数がありますけど。まあいっか。
* forは Cの()がなくなったもの。
* +=で文字列結合可能。
* flag.NArg()はコマンドライン引数の数が
* flag.Arg(num)はnum番目の引数を取り出すのでしょう。
* 配列を渡してこないあたり賢くなってますね。

中身を読んだのでもう一度実行してみます。
コマンドラインなので半角スペースが引数の区切りになるはずです。
ちょっとだけ改造してみました。
package main
import (
	"os"
	"fmt" /* Printを使うため */
	"flag" // command line option parser
)

var omitNewline = flag.Bool("n", false, "don't print final newline")

const (
	Space = " "
	Newline = "\n"
)

func main() {
	flag.Parse() // Scans the arg list and sets up flags
	var s string = "";

	for i:=0 ; i < flag.NArg(); i++ {
		if i > 0 {
			s += Space
		}
		s += flag.Arg(i)
	}
	if !*omitNewline {
		s += Newline
	}
	os.Stdout.WriteString(s)
	fmt.Printf("%d\n",flag.NArg()) /* 引数の個数を出力*/
}
for で:=を使って宣言したiはスコープがforの中に制限されるのですね。
PerlとかC++的には当然のことですが
PHPだと違和感ありますね。Cはそういうことできません。

fmt.Printfの中はテキトウに書いたのですがこれでよいようです。
コンパイルして実行してみましょう。
$ ./8.out

0
動いていそうです。
引数を渡してみると
$ ./8.out echoのテスト その2 その3
echoのテスト その2 その3
3
引数を変えてみましょう。
$ ./8.out echoのテスト その2\ その3
echoのテスト その2 その3
2
期待通り動作しています。

かなり沢山のことがこのechoに詰まっていますが
Cよりユルくて、PHPより固い仕様だとおもいました。
CとかC++とかPythonをよく研究していますね。
どちらかというと既存の言語をあんまり知らない人向けの言語かなぁと。
我ながらひどいまとめですがいまのところはそんなものでいいということにしておきます。

Gccgo

Gccgoという、GoをGCCでコンパイルするバックエンドがあるそうです。
環境はまあもうちょっとわかるようになってからでいいや。
割愛!