好き勝手に・げーあにん?

ファミコンと同い年の社会人ヌルオタの日記

Go 雑感

すでに今更な感じもしますが、ごろごろしながらいじってたので感想でも。

これでゴールーチンをコルーチンっぽく使えるかな?と思ったら失敗したの巻。

package main

func loop(ch chan int, name string) {
  for {
    n := <-ch;
    println("suspended", name, n);
    //ch<-1;
  }
  println("dead");
  //ch<-0;
}

func main() {

  a := make(chan int);
  b := make(chan int);

  go loop(a, "a");
  go loop(b, "b");

  for i := 0; i < 5; i++ {
    a<-i;
    //<-a;
    b<-i;
    //<-b;
  }
}

suspended a 0
suspended b 0
suspended b 1
suspended a 1
suspended a 2
suspended a 3
suspended b 2
suspended b 3
suspended b 4
suspended a 4

aとbが順番どおり呼ばれねーってなった。コメントアウトしているところを有効にすると

suspended a 0
suspended b 0
suspended a 1
suspended b 1
suspended a 2
suspended b 2
suspended a 3
suspended b 3
suspended a 4
suspended b 4

ちゃんと順番に呼ばれるようになりましたとさ。めでたしめでたし。<- してもスレッドの切り替えが促されたりはしないってことなのね、たぶん。go に戻り値が無いから、いちいち監視用に chan を用意してやらないといけないのが、各種コルーチンとか、Erlang の spawn と比べると少々わずらわしい気がしないでもないけど、複数の go にひとつの chan が使われることを想定してたりするならアリなんだと思う。たぶん。

interface の実装がよくわかんね

なんか、思い通りにコンパイルが通らないことがあるんだけどなんで?

package main

type I interface {
  At() int;
  SetAt(v int);
}

type A struct {
  a int;
}

func (x A) At()(int) {
  return x.a;
}

func (x *A) SetAt(v int) {
  x.a = v;
}

func PrintI(x I) {
  println(x.At());
}

func main() {
  var a A;
  a.SetAt(1000);
  PrintI(a);
}

sample.go:27: A is not I
missing SetAt(v int)

って言われてしまう。該当行を

func (x A) SetAt(v int) {

にすれば通るんだけど、ポインタ渡さないとセットにならん。同じようにやっててコンパイルが通ることもあるのが余計によくわからん。Set とかにすると特別な意味あったりする?と思って名前買えてみたり(苦笑)。何か、凡ミスしてるのかもしれないけど、もうわかんね。これで盛大にハマって抜け出せずに、かなり無駄な時間を過ごしてしまった。

以下、雑感

つまらないところでハマってしまって、ギブアップしているので、ネガティブな印象になり気味なことをご了承くだしあ。


参照値渡しは無くて、あくまでポインタか値渡しするしかないのに const が無かったり、private とかもなかったりで、複数人で1つのものを作るのに使うには、だいぶ恐いなーとは思うた。

Matrix44 とかを引数にしたり戻り値にするなら、やっぱりポインタ渡しにしないとダメだよなぁと思うと億劫。サイズがデカめのものを値渡ししても実は速かったりするんだろうか。参照値渡しがなくて、ポインタにするしかないのか、と思うと、凄く C に戻った感が強い。いちいち & 打つのめんどくせー。

interface のしょっぱなでつまづいてしまったので、継承(委譲?)っぽいこととか全然試せなかったorz

unused な変数とか import があると Warning じゃなくて、容赦なく Error にされてイラッとするのは、慣れの問題なんだろうか。使ってないものは消すのが正しいのはわかってるんだけど、チュートリアルを写経してて、一部だけコメントアウトして確認したかったりするときに毎回イラッとしながらやってた。

switch 文は割と好きだよ? case 1,2 とか case i < 0 とかfallthrough とか。

fmt.Printf() とかするときは %#v が便利。 %+v も。

func init()。main() より先に勝手に呼ばれるて、goroutine は始められるけど、実行は init が終わるまで待つ場所。init() 以外で、go しても中身が始まらない方法とかあるんだろうか。実行前だけ特別な場所があるというのがややキモイ。


二次元配列の初期化とかどうすんだ。

a := int{{1,2},{3,4}};

はダメだった。そもそも、go の二次元配列ってどういう扱いなんだ?


ちっちゃいプログラムしか作ってないからわからないけど、コンパイル時間が短いというのは凄い魅力的なんだけどなぁ。

goroutine は良いものではあるので、C っぽい言語で、Erlang とかっぽい並列処理が掛言語としては期待、なのかなぁ。