エディタあれこれ
プログラムを書こうとすると、何かしらエディタが必要なわけで。。メモ帳ではちょっとしんどい。
とーごーかいはつかんきょうっていうものらしい。
まず、ここからダウンロード。僕の環境はWindows 64bitなのでそれを。
で、javaをダウンロード。普通のjava(というか、ブラウザのプラグインのやつ)じゃなくて、JDKとかいうもの。ここから。
eclipseを起動し、help→Install New Softwareを選択、Work withにhttp://goclipse.googlecode.com/svn/trunk/goclipse-update-site/といれてAdd。Add RepositoryにGoClipseといれてOK。
チェックボックスに印をつけ、Next→Next。使用条件のところをよく読んで(読まないけど)accept。Warningが一回でるので気にせずOK。再起動促されるのでOK。
Window→PreferenceからGoを選び、GOROOTを入力。僕の場合はC:\Users\prizeout\bin\go。GOPATHはいれなくても動いた気がするけど、あとでWalkインストールしたついでにいれた。C:\Users\prizeout\bin\go。ディレクトリ構成失敗したかも。。
オートコンプリート機能とかいうのもあるみたい。
gitをインストールして(これは前書いた。若干間インストール間違えたみたいだけど動けばもう獣)
go get -u github.com/nsf/gocode
でよかったと思う。ただこれ非常に重い。僕はいらんのでアンインストールしたいんだけど、どうするのか知らないから放置。
やっぱりemacsだよなぁと思いつつ、当時(一か月前くらい)はemacsがWindowsで動くとは知らなかったので、入れてみた。
たぶんこのへんから落としてきたと思う。解凍する。環境変数XYZZYHOMEに、インストールした(xyzzy.exeがある)ディレクトリを指定。僕の場合C:\Users\prizeout\bin\xyzzy
※環境変数を有効にするためには、一度ログアウトしないといけないっぽい。いい方法ないもんか。
ここからgo-modeのファイルをとってくる。右下あたりにDownload ZIPって書いてあるのでそのへんから。解凍すると、etcとsite-lispというディレクトリがあるので、その中身をそのままxyzzyディレクトリのetcとsite-lispにコピー。
XYZZYHOMEのディレクトリに.xyzzyという名前のファイルを作成。中身に
(load-library "go-mode") (push '("\\.go$" . go-mode) *auto-mode-alist*)
と書いておく。
xyzzyを起動し、M-X byte-compile-file →site-lisp/go-mode.lを指定。やらなくても動いたのでおまじないみたいなものか。
で、*.goというファイルを開くとgo-modeができる。ただこのgo-mode、たまにバグった感じになる。
xyzzyでだいたい不満なかったんだけど、go-modeがたまにバグるし、xmlモードを探してたら、公開をやめてしまってるっぽい。
そんなこんなでmeadowなんかなぁとか思いながら検索したら、emacsがWindowsで使えるじゃないか。
まあこっちの方が拡張機能とか充実してるだろうし、入れてみることにする。
このへんからダウンロード。zipを展開。
環境変数HOMEを設定。ここに.emacs.dというディレクトリが作成されて、設定ファイルとかが入るっぽい。僕はC:\Users\prizeout\homeにした。
ちなみに、これを設定しないと、.emacs.dはC:\Users\prizeout\AppData\Roamingにできる。別にこれでもいいんだけど。。
GOをインストールしたディレクトリのmisc/emacsのふたつのファイルを、emacsをインストールしたディレクトリのsite-lispにコピー。
.emacs.dの下にinit.elというファイルを作成。
(add-to-list 'load-path "PATH CONTAINING go-mode-load.el" t) (require 'go-mode-load)
の二行を書く。
僕は他に
(set-language-environment "japanese") (global-set-key "\C-h" 'backward-delete-char) (setq inhibit-startup-message t)
とりあえずこれだけ書いてる。
まだemacsはそんなに実戦投入してるわけではない。なんだかんだでxyzzyは優秀かもしれない。
今のところこれだけ。viとかは使う予定なし。
追記
9/16 20:04ごろ追記
emacsで改行したあとTABキーを押す、というのが面倒なので、
(add-hook 'go-mode-hook '(lambda() (define-key go-mode-map "\C-m" 'newline-and-indent) ))
というのを追加してみた。少し幸せになれた。
クロージャ
なんかよくわからないものがあるんだけど、まあ関数そのものが変数に代入できて
それで動かすと中身がC言語でいうstatic変数みたいなんになってるんかなと。。
まあよくわからないけどそんなレベルで考えてる。
で、こんなコードを書いてみた。
package main import "fmt" func heke() func(int) int { z := 0 return func(x int) int { z += x return z } } func main() { hekeheke := heke() for i:=0; i<5; i++ { fmt.Println(hekeheke(3)) } }
実行結果は
3 6 9 12 15
これは想定通り
じゃあ、heke()をmain()の中に直接書いたらどうなるんかなと思って
package main import "fmt" func main() { hekeheke := func() func(int) int { z := 0 return func(x int) int { z += x return z } } for i:=0; i<5; i++ { fmt.Println(hekeheke(3)) } }
とやってみた。
これは、コンパイルが通らないみたい。
.\hoge.go:12: too many arguments in call to hekeheke
と言われた。
で、12行目を
fmt.Println(hekeheke()(3))
としてみた。これでコンパイルは通ったんだけど、実行結果は
3 3 3 3 3
うまくいかなかった。
さらに試行錯誤の結果、12行目はそのままにして、10行目(forの前の行)を
}()
とかえてみた。うまくいった。
きっとこれらには意味があることなんだけど、今の僕にはまだよくわかっていない。
golangの関数はよくわからないことがいっぱいあるみたい。
WALKのインストール
windowsのguiでgoを使うには、と、適当に調べてみたらこのへんが見つかった。
で、よろこんで
go get github.com/lxn/walk
とやってみたら、うまくいかない。
なんか$GOPATHが設定されていないらしい。
どこに作るかよくわからないので、C:\Users\prizeout の下にgoというディレクトリを作った。
そのあと、環境変数GOPATHの設定。Windows7では、コントロールパネル→ユーザアカウントから設定するみたい。
もう一度
go get github.com/lxn/walk
やっぱりエラー。gitコマンドが入ってない、と。
前何かでgit入れた気がしないでもないが、ここからダウンロードしてインストール。
インストールはうまくいったっぽい。
さらにもう一度
go get github.com/lxn/walk
同じエラー。そうか、パスが通っていないということか、と今ごろ気づく。
さっきと同じように、環境変数pathに C:\Users\prizeout\AppData\Local\Programs\Git\bin
を追加。
そしてしつこく
go get github.com/lxn/walk
うまくいったっぽい。
今日はこれで満足。コードはそのうち書こう。
goルーチンテスト
func hoge(ch chan int) { v := <- ch v++ fmt.Println(v) ch <- v return } func main() { ch := make(chan int, 1) ch <- 0 for i:=0; i<10; i++{ go hoge(ch) } return }
こんなコードを書いてみた。期待した結果は
1 2 3 4 5 6 7 8 9 10
だったんだが、実際は何も表示されずにプログラムが終了する。
hoge()呼び出しのgoを取るとうまくいく。
小一時間悩んだ結果、goルーチンのhoge()が実行される前にメインのreturnが処理されてプログラムが終了してしまうらしいことに気づいた。
そっか、ということでforループのあとに
time.Sleep(10 * time.Second)
で、終了を遅らせてみて、うまくいった。
並列処理ってちょっとむずかしいけどなんかおもしろいかもしれない。
Walk()つづき
再帰使わずにがんばる方法、寝ようと思ったらなんか思いついたので書いてみた。
type node struct { self *tree.Tree left bool //true: 行ったことあるよー right bool prev *node } func Walk(t *tree.Tree, ch chan int) { now := new(node) now.self = t now.left = false now.right = false var tmp *node for { tmp = now if now.left == false && now.self.Left != nil { //左に行ける now.left = true now = new(node) now.prev = tmp now.self = tmp.self.Left continue } else if now.right == false && now.self.Right != nil { //右に行ける now.right = true now = new(node) now.prev = tmp now.self = tmp.self.Right continue } else if now.prev != nil { //右にも左にも行けないけど親があるとき、処理して親へ ch <- now.self.Value now = now.prev continue } else { //根 ch <- now.self.Value break } } close (ch) return }
if~else if~で書いてたらcontinueいらんやんと思わなくもないが、とりあえず動いてるっぽいのでこれで許してもらおう。
Same()はまたそのうち書こう。
golang練習
先日、goという言語を見つけて、プログラムのリハビリがてらチュートリアルを遊んでいる。
http://go-tour-jp.appspot.com/
んで、がんばって最後の方までいくと、二分木というものがでてきて、それをたどれと。。
情報系の人だったら学校の授業で出てきただろうネタだろうけど、僕にはさっぱり。
んで
func Walk(t *tree.Tree, ch chan int) { ch <- t.Value if t.Left != nil { go Walk(t.Left, ch) } if t.Right != nil { go Walk(t.Right, ch) } return } func main() { ch := make(chan int, 10) go Walk(tree.New(1), ch) }
てなことをやった。
で、chに入ってるものを取り出そうと、
for i := range ch { fmt.Println(i) }
ってやったら、chが閉じてないからずっと待ち続けてるよーってな感じのエラーが出た。
もちろんforループを10回だけ回すのはできるけど、もしこの木のnodeの数が5だったり(今回の問題の仕様では10固定なんだけど)したら、やっぱりエラーになるだろうから、chをうまく閉じられたらと思った。
かといって、Walk()関数の最後にclose(ch)とか書いたら、おそらく再帰などで他で動いているであろうWalk関数のchも閉ざされてしまうだろう。
ということは、再帰を使わずにWalk()関数書かないといけないのか…
どうすんだねと考えてる ←いまここ