Hatena::ブログ(Diary)

はけの徒然日記 このページをアンテナに追加 RSSフィード

2005 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 04 | 05 | 08 | 09 | 10 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 |
2011 | 01 | 02 | 03 | 04 | 11 | 12 |
2012 | 02 | 03 | 05 |
2014 | 02 | 03 | 04 | 05 | 12 |
2015 | 05 | 07 | 08 | 09 | 10 | 11 | 12 |
2016 | 01 | 02 | 04 | 05 | 08 | 09 | 11 | 12 |
2017 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 |

2015-08-31(Mon)

Go言語 - エラー時の戻り値

Go言語にはerrorインターフェース定義されているので、これに適合するエラー構造体を作成して、エラー時にはこの構造体をerror型として返す。

正常終了時には、nil リテラルを返すようにする。

package main

import (
	"fmt"
)

/*
Goで定義されているerror型インターフェース
type error interface{
	Error() string
}
*/

type MyError struct{
	msg string
}
func (m *MyError) Error() string{
	return m.msg
}
func NewMyError(s string) error{
	return &MyError{msg: s}
}


// エラー時にerror型を返す関数
func myFunc(flag bool) error {
	if flag { return NewMyError("Error:エラー発生")}
	return nil
}

func main() {

	fmt.Println( myFunc(true ) )  //-> Error:エラー発生
	fmt.Println( myFunc(false) )  //-> <nil>

}

通常はこっちを使用した方が簡単

package main

import "fmt"

func main() {
	err := fmt.Errorf("error error error") // error型が作成される
	fmt.Println(err)
}

Go言語 - WALKでGUI - 部品を並べる

とりあえずPushButtonを並べてみる。


縦に並べる

f:id:hake:20150831074535j:image

MainWindowのLayoutフィールドにVBoxを指定して、Childrenフィールドの[]Widget部品を入れていく。

ちなみにLayoutをHBoxにすると横に並びます

package main

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

import (
	"fmt"
	"os"
)

type MyMainWindow struct {
	*walk.MainWindow
}

func main() {
	mw := &MyMainWindow {}

	MW := MainWindow{
		AssignTo: &mw.MainWindow,
		Title: "メインウィンドウ",
		MinSize: Size {150, 200},
		Size   : Size {300, 400},
		Layout: VBox {},
		Children: []Widget {
			PushButton {
				Text: "PB0",
			},
			PushButton {
				Text: "PB1",
			},
			PushButton {
				Text: "PB2",
			},
		},
	}


	if _, err := MW.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}


各段内で横に並べる

続きを読む

2015-08-30(Sun)

Go言語 - WALKでGUI - 何もないウィンドウ

ネット上に(日本語の)情報がほとんど無いのでドキュメントを見ながら勉強

環境は、Windows8.1(32bit)上のGo言語1.5+WALKライブラリです。


ドキュメントは、GoDocServerを起動した状態で、

http://localhost:6060/pkg/github.com/lxn/walk/

を参照。walk直下に各ウィジェットで使えるメソッドが、declarativeの下に各ウィジェットが持っているフィールドとイベント情報がある。


とりあえず何もないウィンドウを作ってみる。

MainWindowのイベントとして

    OnKeyDown        walk.KeyEventHandler
    OnKeyPress       walk.KeyEventHandler
    OnKeyUp          walk.KeyEventHandler
    OnMouseDown      walk.MouseEventHandler
    OnMouseMove      walk.MouseEventHandler
    OnMouseUp        walk.MouseEventHandler
    OnSizeChanged    walk.EventHandler

が用意されていますが、マウス関係は現状動作しないみたいです。(2015/11/26追記 動作する様になりました。)

下記はサイズ変更とキー押下イベントの結果を標準出力に出力するプログラム

続きを読む

2015-08-29(Sat)

Go言語 - 複数ファイルのコンパイル

同packageの場合

ファイル中の小文字で始まる関数や変数も参照可能。

同じフォルダに置きソースファイル名を指定しないでコンパイルする。実行ファイル名はフォルダ名になる。

\add\main.go
    \add.go

main.go

package main

import (
	"fmt"
)

func main() {
	fmt.Println(add(1, 2))  //-> 3
	fmt.Println(foo)        //-> 10
}

add.go

package main

var foo int = 10


func add(x, y int) int {
	return x + y
}



他packageを使用する場合

他のソースファイルをimportして使用する。他ファイル中の大文字で始まる関数や変数のみ参照可。

importするpackage名とフォルダ名を同じにする。ファイル名はpackage名と異なっても良い。

main.go指定してコンパイルする。

  \main.go
  \calc\func1.go
  \calc\func2.go

main.go

package main

import (
	"fmt"
	"./calc"
)

func main() {
	fmt.Println(calc.Add(1, 2))   //-> 3
//	fmt.Println(calc.mul(1, 2))   //-> undefined: calc.mul
	fmt.Println(calc.Sub(10, 5))  //-> 5
	fmt.Println(calc.Foo)         //-> 10
//	fmt.Println(calc.bar)         //-> undefined: bar
}

func1.go

package calc

var Foo int = 10
var bar int = 20

func Add(x, y int) int {
	return x + y
}

func mul(x, y int) int {
	return x * y
}

func2.go

package calc

func Sub(x, y int) int {
	return x - y
}

2015-08-28(Fri)

Go言語 - 正規表現

日本語も一文字として認識してくれるみたい。

でも、文字の位置を返すメソッドバイトスライスの位置なのでで注意。

package main

import (
	"fmt"
	"regexp"
)

func main() {

	s := "aあbいcうdえeおf"

	// 正規表現にマッチするかの有無
	fmt.Println(regexp.MatchString("あ.", s)) //-> true <nil>
	fmt.Println(regexp.MatchString("か.", s)) //-> false <nil>

	// 正規表現パターンのコンパイル
	re1 := regexp.MustCompile("..")
	re2 := regexp.MustCompile(".*")

	// マッチした文字列のスライスを返す
	fmt.Println(re1.FindAllString(s, -1)) //-> [aあ bい cう dえ eお]
	fmt.Println(re1.FindAllString(s,  2)) //-> [aあ bい]
	fmt.Println(re2.FindAllString(s, -1)) //-> [aあbいcうdえeおf]


	re3 := regexp.MustCompile(".(.)(.).")

	// [マッチした文字列, キャプチャ文字列1, ……]を要素とするスライスを返す
	fmt.Println(re3.FindAllStringSubmatch(s, -1)) //-> [[aあbい あ b] [cうdえ う d]]
	fmt.Println(re3.FindAllStringSubmatchIndex(s, -1)) //-> [[0 8 1 4 4 5] [8 16 9 12 12 13]]
	                                            //    マッチした要素のbyte列でのスライス値を表示

	// 最初にマッチした文字列
	fmt.Println(re1.FindString(s)) //-> [aあ]   // マッチしない場合は空文字列""を返す。

	// マッチした文字列を置換
	fmt.Println(re3.ReplaceAllLiteralString(s, "$1")) //-> $1$1eおf   $1は文字

	fmt.Println(re3.ReplaceAllString(s, "$1")) //-> あうeおf          $1は最初にキャプチャされた文字
	fmt.Println(re3.ReplaceAllString(s, "$2")) //-> bdeおf            $2は2番目にキャプチャされた文字

}

2015-08-27(Thu)

Go言語 - ソート

sortパッケージで、int,float64,stringのスライスについての小さい順のソートが可能。

逆順が欲しい場合は予め定義されているスライス型(intならIntSlice)にしてからsort.Sort(sort.Reverse(x))とする必要がある。でも、普通にソートして並べ替えた方が単純に思える。

package main

import (
	"fmt"
	"sort"
)
func main() {
	a := []int{2,4,6,5,3,1}
	fmt.Println(a)
	fmt.Println( sort.IntsAreSorted(a) ) //-> false ソート済みならtrue
	sort.Ints(a)
	fmt.Println(a)                     //-> [1 2 3 4 5 6]
	fmt.Println(sort.IntsAreSorted(a)) //-> true
	sort.Sort(sort.Reverse(sort.IntSlice(a)))
	fmt.Println(a)                     //-> [6 5 4 3 2 1]
}

新しい型のソート

新しく定義した型のソートを行う場合は、インターフェース定義されている3つの関数作成する必要がある。

type Interface interface {
	Len() int
	Less(i, j int) bool
	Swap(i, j int)
}

以下は、[]intをmyint型に定義して、3に近い順のソートを行う例。

package main

import (
	"fmt"
	"sort"
)

type myint []int
func(a myint) Len() int {
	return len(a)
}
func(a myint) Less(i, j int) bool {
	return myAbs(3 - a[i]) < myAbs(3 - a[j])  // 3に近い方が小
//	return a[i] < a[j]
}
func(a myint) Swap(i, j int) {
	t := a[i]
	a[i] = a[j]
	a[j] = t
	return
}

// 絶対値を求める
func myAbs(x int) int {
	if x < 0 { x = x * -1}
	return x
}

func main() {

	// 3に近い順のソート
	b := myint{12,-1,2,4,6,5,3,1}
	fmt.Println(b)
	sort.Sort(b)
	fmt.Println(b)       //-> [3 2 4 5 1 6 -1 12]

}

2015-08-26(Wed)

Go言語 - マップ

rubyでいうところのハッシュ

for rangeで取り出す場合は、キーのみと、キー&値のペアの取り出しができる。

キー指定して値を読みだす場合、そのキー対応する値が無い場合は二番目の戻り値がfalseになり、値(最初戻り値)はゼロ値になる。

package main

import (
	"fmt"
)


func main() {

	m := map[string]int {
		"foo" : 1,
		"bar" : 2, 
		"baz" : 3,   // } を改行する場合はカンマが必要
	}

	// キーのみ取り出し
	for k := range m {
		fmt.Println(k)  //-> foo, bar, baz(順番は不定)
	}

	// キーと値の取り出し
	for k, v := range m {
		fmt.Println(k, v)  //-> foo, 1 ……(順番は不定)
	}

	// 値のないキーを指定
	v := m["zzz"]
	fmt.Println(v)  //-> 0 ゼロ値

	// 二つ目の戻り値がbool,値が無い場合はfalse
	v, b := m["zzz"]
	fmt.Println(v, b)  //-> 0 false

	// 値がある場合はtrue
	v, b  = m["foo"]
	fmt.Println(v, b)  //-> 1 true
}

Go言語 - 日本語文字列の操作

stringバイト列なので、日本語文字列インデックス指定で取り出しても文字単位指定とはならない。文字単位指定する場合には一旦runeのスライスに変換すると、インデックスが文字単位と一致する。

また、rangeを使用したforの中でも文字単位(rune)で取り出せる。

package main

import (
	"fmt"
)

func main() {

	var s string = "あaいbうc"

	// stringのスライスはバイト単位
	fmt.Println(s[:3])         //-> あ
	fmt.Printf("%x\n", s[:3])  //-> e38182
	fmt.Println(s[:4])         //-> あa
	fmt.Printf("%x\n", s[:4])  //-> e3818261


	// stringを一旦runeのスライスに変換して操作する。
	rs := []rune(s)
	fmt.Println(string(rs[:2]))    //-> あa


	// for文もインデックス指定はバイト単位
	for i := 0; i < len(s); i++ {
		fmt.Printf("%T\n", s[i])   //-> uint8(byteはuint8のエイリアス)
		fmt.Println(s[i])          //-> 227,……
	}

	// rangeで取り出すとrune単位で取り出せる。
	for _, c := range s {
		fmt.Printf("%T\n", c)   //-> int32(runeはint32のエイリアス)
		fmt.Println(string(c))  //-> あ,……
	}
}

2015-08-25(Tue)

Go言語 - 関数を引数にする関数

関数MyMapIntの第一引数は、一つのintを引数にして、intを返す関数

package main

import (
	"fmt"
)

func MyMapInt(fn func(int) int, sl []int) (ret []int) {
	ret = make([]int, 0, len(sl))
	for _, n := range sl {
		ret = append(ret, fn(n))
	}
	return
}

func twice(x int) int {
	return x*2
}

func square(x int) int {
	return x*x
}

func main() {
	a := []int{1, 2, 3, 4, 5}
	fmt.Println(MyMapInt(twice,  a)) //-> [2 4 6 8 10]
	fmt.Println(MyMapInt(square, a)) //-> [1 4 9 16 25]
}

2015-08-24(Mon)

Go言語 - スライス

Go言語では一旦作成された配列の要素数は変更できない。スライスは配列への参照だけれども要素数の変更は可能。スライスに要素が追加されて、配列キャパシティを超えた場合には、より大きなキャパシティを持った配列と、そのスライスが作成されて要素の値がコピーされる。

従って、二つの変数が同じスライスを参照していて、一方の要素をキャパシティ以上に増やした場合には、その変数は新しいスライスを参照することになる。

package main

import "fmt"

func main() {

	a := make([]int, 8, 8)
	a[7] = 9
	b := a
	b[6] = 8

	// a と b は、同じスライス。
	fmt.Println(a)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(a))  // -> 8 要素数
	fmt.Println(cap(a))  // -> 8 キャパシティ

	fmt.Println(b)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(b))  // -> 8
	fmt.Println(cap(b))  // -> 8


	// a に1要素追加
	// 要素数がキャパシティを超えた為、新しい配列のスライスになる。
	a = append(a, 10)

	// a と b は、異なるスライス
	a[0] = 1
	fmt.Println(a)       // -> [1 0 0 0 0 0 8 9 10]
	fmt.Println(len(a))  // -> 9
	fmt.Println(cap(a))  // -> 16

	fmt.Println(b)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(b))  // -> 8
	fmt.Println(cap(b))  // -> 8


}


スライスは参照

スライスは実体の配列への参照なので、関数の引数で渡した場合は参照がそのまま渡される。

従って関数の中でスライスの要素を変更した場合は、元のスライスも変更される。ただし要素数を変更した場合は、関数内で新しいスライスが生成されるため、元のスライスに影響を与えない。

package main

import "fmt"

func incInt(i *int){
	*i++            // 関数外の実体を変更する場合はポインタ指定が必要
}

func incSlice(lis []int, idx int){
	lis[idx]++                   // 元のスライスも変更される

	lis = append(lis, 100)       // 要素を追加
	fmt.Println(lis)             //-> [1 3 3 100]
}                                    // 新規スライスが作成されるので
                                     //   元のスライスに影響なし

func main() {
	var i int = 1
	fmt.Println(i)      //-> 1
	incInt(&i)
	fmt.Println(i)      //-> 2

	s := []int{1,2,3}
	fmt.Println(s)      //-> [1 2 3]
	incSlice(s, 1)
	fmt.Println(s)      //-> [1 3 3]

}

Go言語 - 埋め込みによる構造体の継承

構造体Fooを構造体Barに埋め込む(フィールド名をつけないメンバとする)ことで、継承の様なことができる。

package main

import "fmt"

type Foo struct {
	name string
}
func(f *Foo)hello() {
	fmt.Println("Hello", f.name)
}

type Bar struct{
	Foo
}
func(b *Bar)bye() {
	fmt.Println("Bye", b.name)
}

func main() {
	var f Foo
	f.name = "taro"
	f.hello()                //-> Hello taro
	
	g := &Foo{"jiro"}
	g.hello()                //-> Hello jiro

	h := &Bar{Foo{"hanako"}}
	h.hello()                //-> Hello hanako
	h.bye()                  //-> Bye hanako

}


メソッドのオーバーライド?

埋め込む構造体と埋め込まれる構造体に同じメソッドがある場合は、埋め込む構造体(継承された構造体?)のメソッドが有効になる。

package main

import "fmt"

type foo struct {
	i int
}
func (self *foo)get() int {
	return self.i
}

type bar struct {
	foo
}
func (self *bar)get() int {   // fooと同じ名前のメソッド
	return self.i*2
}


func main() {
	a := &bar{foo{10}}

	fmt.Println(a.get()) //-> 20
}

2015-08-23(Sun)

Go言語 - インターフェース

インターフェースの使用方法勉強

いまひとつ理解できていないような気がしますが……

あるインターフェース型で宣言した変数や関数の仮引数は、そのインターフェース型で定義したメソッドを持つデータ型のみ代入可能ということで良いのかな?

あるインターフェース型を仮引数にした場合、その仮引数は確実に定義したメソッドが使えるということが保障される。

反対に考えると、メソッドを何も定義していないインターフェース型は、どんなデータ型でも受け取ることができるということ。


package main

import "fmt"

type StS struct{              // stringを返すGetメソッドを持つ構造体
	v string
}
func (t *StS) Get() string {
	return t.v
}

type StI struct{              // intを返すGetメソッドを持つ構造体
	v int
}
func (t *StI) Get() int {
	return t.v
}

type StN struct{}             // メソッドを持たない構造体



type mystring string         // stringを返すGetメソッドを持つ他の型を定義
func (t mystring) Get() string {
	return string(t)
}




type GetterS interface {     //  インターフェースとして
	Get() string         //    stringを返すGetメソッドを定義
}
func PrintS(i GetterS){      //  GetterS型を引数に持つ関数
	fmt.Println(i.Get())
}



type AllOK interface{}       // メソッドを持たないインターフェース型
func PrintA(i AllOK){        // AllOK型を引数に持つ関数
	fmt.Println(i)
}



func main() {

	// interface GetterS型の変数の宣言
	var a, e    GetterS
//	var b, c, d GetterS

	var x mystring = "baz"


	// interface GetterS型の変数には、pointer receiverを持ち、
	//   stringを返すGetメソッドを持つ型のみ代入可能

	a = &StS{"foo"} // ok

//	b = StS{"bar"}  // レシーバがポインタで無いのでエラー
                    // cannot use StS literal (type StS) as type GetterS in assignment:
                    // StS does not implement GetterS (Get method has pointer receiver)

//	c = StI{10}     // 戻り値の型が違うのでエラー
                    // cannot use StI literal (type StI) as type GetterS in assignment:
                    // StI does not implement GetterS (wrong type for Get method)
                    // have Get() int
                    // want Get() string

//	d = StN{}       // Getメソッドが無いのでエラー
                    // cannot use StN literal (type StN) as type GetterS in assignment:
                    // StN does not implement GetterS (missing Get method)

        e = x           // ok


	fmt.Println(a.Get()) // -> foo
	fmt.Println(e.Get()) // -> baz

	// GetterS型インターフェースを引数に持つ関数
	PrintS(a)    // -> foo
	PrintS(e)    // -> baz






	// AllOK型インターフェースを引数に持つ関数
	PrintA(&StS{"foo"}) // -> &{foo}
	PrintA(StS{"bar"})  // -> {bar}
	PrintA(StI{10})     // -> {10}
	PrintA(StN{})       // -> {}
	PrintA(x)           // -> baz

}

Go言語 - 構造体とメソッド

Go言語1.5が公開されたので入替。


構造体とメソッド使用方法勉強

注意点として、ポインタ経由で参照渡しされた構造体のフィールドへのアクセス時に *p.hoge のようにアスタリスクをつけるとエラーになる。

package main

import "fmt"

type Test struct{
	Num int              // 先頭が大文字のフィールドはpublic(外部からアクセス可)
	Str string
}

func (t Test) SetStr1(s string){
	t.Str = s                       // tは値渡し(コピー)なのでオリジナルは変更されない。
}

func (t *Test) SetStr2(s string){
	t.Str = s                       // tは参照渡し
}                                       // 左辺を *t.Str とするとエラー


func NewTest(i int, s string) *Test{    // 新しいTest型構造体への参照を返す関数
	return &Test{
		i,
		s,      // '}'を改行する場合は、ここにカンマが必要
	}
}


func main() {

	// 構造体Test型の宣言と、初期化
	var a Test = Test{1,"foo"}              // フィールドの宣言順で初期化
	var b Test = Test{Str: "bar", Num: 2}   // フィールド名を指定して初期化、順番は無関係
	var p *Test = &Test{3, "baz"}           // ポインタで作成した構造体を参照
	q := NewTest(4, "qux")                  // 関数で構造体を作成
	fmt.Printf("type of q : %T\n", q)       //->  type of q : *main.Test
                                                //     q はTEST型構造体へのポインタ



	// フィールド値のリード
	fmt.Println("Num :", a.Num, "String :", a.Str) //-> Num : 1 String : foo
	fmt.Println("Num :", b.Num, "String :", b.Str) //-> Num : 2 String : bar
	fmt.Println("Num :", p.Num, "String :", p.Str) //-> Num : 3 String : baz
	fmt.Println("Num :", q.Num, "String :", q.Str) //-> Num : 4 String : qux

	// フィールド値の変更
	a.Str = "hoge"
	p.Str = "piyo"      //  左辺を *p.Str とするとエラーになる。
	fmt.Println("Num :", a.Num, "String :", a.Str) //-> Num : 1 String : hoge
	fmt.Println("Num :", p.Num, "String :", p.Str) //-> Num : 3 String : piyo


	// レシーバの値渡しメソッド(レシーバのフィールド値を変更できない)
	a.SetStr1("hello")
	fmt.Println("Num :", a.Num, "String :", a.Str) //-> Num : 1 String : hoge


	// レシーバの参照渡しメソッド(レシーバのフィールド値を変更できる)
	a.SetStr2("hello")
	fmt.Println("Num :", a.Num, "String :", a.Str) //-> Num : 1 String : hello
	p.SetStr2("good bye")
	fmt.Println("Num :", p.Num, "String :", p.Str) //-> Num : 3 String : good bye
}

2015-08-17(Mon)

Go言語 - Shift_JISファイルの読み書き

Windowsでの使用ではSJISテキストを扱うことが多くなります。SJISファイルの読み書きには以下のパッケージを使用します。

参考サイト

Go で euc-jp や sjis の csv ファイルを読み込むには変換用のリーダーを1つかませるだけでよかった

入手先

https://github.com/golang/text

参考サイトとパッケージのパス?が違うので注意。

旧
"code.google.com/p/go.text/encoding/japanese"
"code.google.com/p/go.text/transform"

新
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"

サンプル

package main

import (
    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
    "bufio"
    "fmt"
//  "io"
    "os"
)

func main() {
    var fp *os.File
    var err error

//  var byteBuf   []byte
//  var tooLong   bool

    //
    // Shift_JISファイルを読み込み
    //
    fp, err = os.Open("SJIS.txt")
    if err != nil {
        panic(err)
    }
//  defer fp.Close()

    sjisScanner  := bufio.NewScanner(transform.NewReader(fp, japanese.ShiftJIS.NewDecoder()))

    // 1行ずつ処理
    for sjisScanner.Scan() {
        fmt.Println(sjisScanner.Text())  // コマンドプロンプトにはShift_JISに自動でエンコードされる
    }

//  sjisReader  := bufio.NewReader(transform.NewReader(fp, japanese.ShiftJIS.NewDecoder()))
    // 1行ずつ処理
//  for {
//      byteBuf, tooLong, err := sjisReader.ReadLine()
//      if err == io.EOF {
//          break
//      } else if err != nil {
//          panic(err)
//      }
//      if tooLong {
//          panic("***Line is too Long!!***")
//      }
//      str := string(byteBuf)
//      fmt.Println(str)  // コマンドプロンプトにはShift_JISに自動でエンコードされる
//  }
    fp.Close()



    //
    // Shift_JISでファイルに書き込み
    //
    fp, err = os.OpenFile("SJIS2.txt", os.O_CREATE|os.O_WRONLY, 0666)
    if err != nil {
        panic(err)
    }
    defer fp.Close()
    sjisWriter  := bufio.NewWriter(transform.NewWriter(fp, japanese.ShiftJIS.NewEncoder()))

    // 以下エラー処理省略
    _, err = sjisWriter.WriteString("SJIJライトデータ1行目\n")
    _, err = sjisWriter.WriteString("SJIJライトデータ2行目\n")
    err    = sjisWriter.Flush()

//  fp.Close()

}

2015-08-16(Sun)

Go言語でGUIプログラム on Windows

VisualuRubyが使用できなくなってからexeファイル単体で動作して、かつ、ファイルサイズが巨大にならないGUIアプリ制作環境を探していましたが、Go言語+WALKライブラリがなかなか良さげなのでメモ

後述のhello.exeの実行ファイルサイズは5MB弱で、Windows 8.1(32bit)でコンパイルした実行ファイルWindows Vistaでも動作しました。


入手先


参考サイト


その他

改訂2版 基礎からわかる Go言語

改訂2版 基礎からわかる Go言語


  • こんな本も出版されました(2016/04追記)
スターティングGo言語 (CodeZine BOOKS)

スターティングGo言語 (CodeZine BOOKS)


  • さらに追加(2016/06追記)

インストール

Go言語本体msi(今回は go1.4.2.windows-386.msi)をダウンロードして、そのままインストールする。デフォルトインストール先はC:\GO です。

zipを使用した場合は、環境変数GOROOTを設定(C:\GO)する。


WALKライブラリは以下のコマンドを実行する。(要Git他)

go get github.com/lxn/walk

今回はPC必要なアプリ(Git)をインストールしていなかったので、walkフォルダwinフォルダzipファイルダウンロードして、C:\GO\src以下に展開しました。

C:\Go\src\github.com\lxn\walk\*
C:\Go\src\github.com\lxn\win\*

コンパイル

ソースを置いた場所で以下のコマンドを実行します。

go build src.go                               CUIアプリ
go build -ldflags="-H windowsgui" src.go      GUIアプリ(DOS窓を表示させない)
go build -ldflags="-s -H windowsgui" src.go   stripをかけてサイズ縮小

コマンドで、ソースファイル名を省略した場合(同package名の複数ソースファイルがある場合など?)は「フォルダ名」.exeが作成されます。またWALKライブラリを使用する場合は「実行ファイル名」.manifestという名前マニフェストファイルを同じ場所に置いておかないと起動しないので注意が必要マニフェストファイルコピーしてファイル名だけを変更して(内容はいじらない)使いまわせます。

サンプル

当方Go言語関連の記事も参照ください。


以下は、ボタンクリックすると"Hello 世界!"と表示するプログラムです。ソースutf-8で保存します。

ライブラリの使用方法は参考サイトや、ライブラリのexampleを参照のこと、VisualuRubyを使用していたのでそんなに違和感なく使用できそうです。

f:id:hake:20150902204602j:image

hello.go

続きを読む