ぷらこのきろく

メモとかテストとか備忘録とか

walk初め

walkを使おうとぐうぐる先生に聞いてみたが、
ここここしか見つからなかった。
それらの書いてあることはきっと初歩的なことなんだろうけど、今の僕にはまだむずかしい。
僕はまずhello worldが書きたい。

というわけで、よくわからんまま

package main

import (
//	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

func main() {
	
	MainWindow{
		Title: "hello",
		MinSize: Size{320, 240},
		MaxSize: Size{800, 600},
		Size: Size{640, 480},
	}.Run()
}

これだけ書いて動くかどうか試してみる。
f:id:prizeout:20130917024533j:plain
一応動いた。
ただ、MinSizeはちゃんとなって、それ以上ウインドウが小さくならないようになるんだけど、MaxSizeはうまく機能しない。なんでだろう。

あとの部分は、declarative/mainwindow.goにいろいろいっぱい書いてあるので、それをひとつずつ見ながら遊んでみるのかな。

skkのインストール

やっぱりskkは入れないとね、と、入れてみた。

ここからskk本体をダウンロードして解凍。なんかddskk-20130915.tar.gzという、昨日の日付のがあったのでそれを入れてみた。毎日開発されてる開発バージョンなのかな?
ここからSKK-JISYO.L をダウンロードして解凍。skkを展開したところのdicというディレクトリにコピー。
makeit.batを編集。

set PREFIX=
set EMACS=
set LISPDIR=
set DEFAULT_MAKE_ARG=

という部分があるので、そこを適当に埋める。僕の場合

set PREFIX=C:\Users\prizeout\bin\emacs
set EMACS=C:\Users\prizeout\bin\emacs\emacs-24.3\bin/emacs.exe
set LISPDIR=%PREFIX%\emacs-24.3\site-lisp
set DEFAULT_MAKE_ARG=

こんな感じで埋めてみた。%EMACS%のところがフルパスになってるのはそこを最初に書いたから。
そして、コマンドプロンプト

maikit.bat install

emacsを起動して、C-x C-j。うまくいったっぽい。

エディタあれこれ

プログラムを書こうとすると、何かしらエディタが必要なわけで。。メモ帳ではちょっとしんどい。

とーごーかいはつかんきょうっていうものらしい。
まず、ここからダウンロード。僕の環境は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()はまたそのうち書こう。