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-09-30(Wed)

Go言語 - データのランダムシャッフル

ライブラリシャッフルがなさそうだったので作成。Fisher-Yates shuffleというアルゴリズム使用しました。

package main

import "fmt"
import "time"
import "math/rand"

func shuffle(list []int){
	for i := len(list); i > 1; i-- {
		j := rand.Intn(i)          // 0〜(i-1) の乱数発生
		list[i - 1], list[j] = list[j], list[i - 1]
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())

	// データ要素数指定、および初期データ作成
	size := 10
	list := make([]int, size, size)
	for i := 0; i < size; i++ { list[i] = i }

	// シャッフル
	shuffle(list)

	for _, d := range list {
		fmt.Println(d)
	}
}

2015-09-29(Tue)

Go言語 - 巨大な数を扱う

math/bigライブラリを使用することで巨大な整数や有理数を扱うことができます。

フィボナッチ数列を表示するプログラム

package main
import (
	"fmt"
)

func main() {

	var f0 uint64 = 1
	var f1 uint64 = 1

	for i := 1; i < 100; i++ {
		fmt.Println(i,f0)
		f0, f1 = f1, f0+f1
		if f1 < f0 {
			fmt.Println("Out of Range")
			break
		}
	}
}

結果

uint64型でも93項目でオーバーフローを起こします。

1 1
2 1
3 2
4 3
5 5


91 4660046610375530309
92 7540113804746346429
Out of Range

math/bigを使用したフィボナッチ数列プログラム

package main
import (
	"fmt"
	"math/big"
)

func main() {

	f0 := big.NewInt(1)
	f1 := big.NewInt(1)
	tmp := big.NewInt(0)

	for i := 1; i < 1001; i++ {
		fmt.Println(i,f0.String())
		tmp.Add(f0, f1)
		f0, f1 = f1, tmp
		if f1.Cmp(f0) == -1 {
			fmt.Println("Out of Range")
			break
		}
	}
}

結果

どこまででも?計算できる。

とりあえず1000項まで。

999 2009078638474251226778296966987503394802634021947875513957031978194408220859
25522967474696027942973398924001172041215029722589741067308883174710829525598277
57377314577795433097664514884491945891021164091536962140594216139876372689173435
39489889449296482099339566226656436330593434867072531976062763008
1000 401815727694850245355659393397500678960526804389575102791406395638881644171
85104593494939205588594679784800234408243005944517948213461776634942165905119655
51475462915559086619532902976898389178204232818307392428118843227975274537834687
078979778898592964198679132453312872661186869734145063952125526016

2015-09-27(Sun)

Go言語 - 無名関数とクロージャ

ある関数foo内で定義された無名関数は、foo内のローカル変数にアクセスできる。

package main
import "fmt"

func foo() {
	var s string = "hello foo"
	
	f := func(){
		fmt.Println(s)
	}
	f()
}

func main() {
	foo() //-> hello foo
}

関数fooの戻り値として返された無名関数も同様にローカル変数にアクセスできる。

package main
import "fmt"

func foo() func(){
	var s string = "hello foo"
	
	f := func(){
		fmt.Println(s)
	}
	return f
}

func main() {
	a := foo()
	a()         //-> hello foo

そして、その関数foo内のローカル変数の値は無名関数毎に保存される。

こういうのをクロージャというらしい、以前から単語だけは目にしていましたが初めて理解できた気がします。

package main
import "fmt"

func foo(m string) func(string){
	var s string = m
	
	f := func(n string){
		fmt.Println(s + n)
	}
	return f
}

func main() {
	hello := foo("hello ")
	bye   := foo("bye ")
	hello("Taro")          //-> hello Taro
	bye("Hanako")          //-> bye Hanako
	hello("Jiro")          //-> hello Jiro
}

続きを読む

2015-09-25(Fri)

Go言語 - EXCELファイル操作

xlsx形式エクセルファイルを読んだり、新規作成したりできます

ただし、xlsxファイルを開いて、そのファイルを変更保存する。あるいは変更した内容を別名保存すると、その保存したファイルExcelで開くときに内容を修復する旨のメッセージがでます(Excel2013で確認


入手先


実行結果

  • 実行前

f:id:hake:20150925191014j:image


  • 実行後
1-A 1-B 1-C
2-A 2-B 2-C
3-A 3-B 3-C

2-B

2-A B-2 2-C

f:id:hake:20150925191015j:image


続きを読む

2015-09-23(Wed)

Go言語 - goyaccで構文解析

Go言語にはgoyaccという構文解析ツールがあるので一番単純な整数の四則演算を行うプログラム作成してみました。

以下は作成ポイントとなるメモです。

参考サイト


lex.Lexer(lex/lexer.go

先日作成した字句解析プログラムを少し修正してpackage lexとする。修正点は以下のとおり。

func (self *Lexer)Scan() int
func (self *Lexer)Text() string
func (self *Lexer)Line() int
func (self *Lexer)Column() int

Lexer(paeser.go.y)

goyaccから呼ばれるLexerを定義し、そこにlex.Lexerを埋め込みます。フィールド変数resultは構文解析の結果を格納しmain関数に渡す変数(今回は整数演算なのでint型)で、cLineとcColはエラー時に表示する位置を格納しています

LexerはParserのyyParseで使用する為に、interface型として、LexメソッドErrorメッソドを定義する必要があります

type Lexer struct {
	lex.Lexer
	result  int
	cLine   int
	cCol    int
}

func (l *Lexer) Lex(lval *yySymType) int
func (l *Lexer) Error(e string)

Lexメソッド戻り値は各トークン種別(int)になります。ただし、ここで使用されるトークン種別は、後述の%tokenで定義された独自の値(int)が割り振られる為にlex.Lexer.Scan()が返す値を、この値に変更する必要があります

func (l *Lexer) Lex(lval *yySymType) int {
	token := l.Scan()
	if token == lex.NUMBER {
		token = NUMBER
	}
          ……
	return token

Lexメソッド引数yySymTypeは、%union{…}で定義したフィールド変数をメンバに持つ構造体となりますLexメソッドが呼ばれるごとに必要に応じて取得したトークン情報をyySymTypeに渡します

func (l *Lexer) Lex(lval *yySymType) int {
	token := l.Scan()
          ……
	lval.token = Token{token: token, literal: l.Text()}
          ……
	return token
}

Parser部(paeser.go.y)

トークンおよび構文の中で使用する型を定義しています

%union{
	token Token
	num   int
}

構文の中の各非終端記号(type)と終端記号(token)の型を定義しています。<…>が%unionで定義したフィールド変数名になります

%type<num> program
%type<num> expr
%token<token> NUMBER

構文のトップでLexrerのフィールド変数resultに結果を代入して、main()に渡します

program
	: expr
	{
		$$ = $1
		yylex.(*Lexer).result = $$
	}

その他は基本的c言語で使用するyacc(bison)と同じ記述になります


続きを読む

2015-09-20(Sun)

Go言語 - Set(集合)

本日からGo言語の使用環境は、go version go1.5.1 windows/amd64 です。


Goでsetを扱う方法を見てSet型を作成してみました。

続きを読む

2015-09-19(Sat)

新PC購入 & Windows10アップグレード

前回のレッツノート購入から7年半ぶりの新PC購入です。

Windows10プリインストールモデルまで待とうかとも思いましたが、近場の家電量販店Windows8.1モデルが底値かなということでモバイル用途PCレッツノートの後継)のみ購入しました。初64bit環境となりました。

自宅用はWindows10プリインストールモデルが出てからなるべくスペックの良いもの(長く使用できそうなもの)を購入予定です。


1日かけてWindows10 Homeにアップグレードしましたが特に問題なく移行できそうです。

東芝 dynabook KIRA V63/PS

東芝 dynabook KIRA V63/PS

メモ

2015-09-18(Fri)

Go言語 - WALKでGUI - ListBox

ListBoxの使用例。ウィンドウ上がListBox。

表示項目をstringのスライスにしてModelフィールドに置くことで表示させます。各項目はクリックおよびダブルクリックイベントが発生します

ボタンクリックで項目を追加しています方法はListBox.Model()で項目リストを取得します。これはインターフェース型なのでストリングのスライスに型アサーション実施してappend()で項目を追加後、Modelフィールドに再設定します


f:id:IL_Levante:20150918192539j:image

続きを読む

2015-09-15(Tue)

Go言語 - 字句解析プログラム

勉強がてら字句解析プログラム作成してみました。

Lexser.Scan()を実行する毎に、sample.txtから文字(rune)ずつ読み込み、1トークンを読み込んだら、そのトークンの書かれている行、桁、トークン種類、トークンリテラル文字列を表示します

数字はNUMBERトークンダブルクォートで囲まれた文字列STRINGトークン、英字とアンダースコアで始まる英数字列はIDENTトークンとなります。ただし英数字列の内、TokenTableに登録されているものは予約語として対応する種類のトークンになります

ファイル終端(EOF)に到達後にLexser.Scan()が実行された場合はEOFトークンが返されます


sample.txt

package main

import "fmt"

var abc int
abc = 10

結果

line:  1  col:  0  kind:    IDENT  str: package
line:  1  col:  8  kind:    IDENT  str: main
line:  3  col:  0  kind:    IDENT  str: import
line:  3  col:  7  kind:   STRING  str: fmt
line:  5  col:  0  kind:      VAR  str: var
line:  5  col:  4  kind:    IDENT  str: abc
line:  5  col:  8  kind:      INT  str: int
line:  6  col:  0  kind:    IDENT  str: abc
line:  6  col:  4  kind:    OTHER  str: =
line:  6  col:  6  kind:   NUMBER  str: 10
line:  7  col:  0  kind:      EOF  str: <EOF>
line:  7  col:  0  kind:      EOF  str: <EOF>

続きを読む

2015-09-08(Tue)

Go言語 - WALKでGUI - DialogBox

DialogBoxの使用例。

DialogBoxで入力した文字列をMain Windowに表示させています

Main側と同様にDialogのレイアウトと実体用の構造体を用意します。一点だけ追加として、DefaultButtonとCancelButtonフィールドに各々対応するPushButtonの実体を割り当てます

ダイアログを開く関数RunMyDialogの第二引数として、MyDialogData型構造体の参照を渡してMainとDialog間のデータやりとりを行っています関数戻り値は、Dialog側で閉じるときにクリックされたキー情報が返されます

Dialog側では、OKボタンクリックされたときに入力されたデータをMyDialogData型構造体に退避しています


f:id:hake:20150908185339j:image

続きを読む

2015-09-06(Sun)

Go言語 - break先のラベルの位置

二重のforループからの脱出先として、forブロックの下にラベルを書いたらエラーになりました。どうやらforブロックの上に書くのが正解みたい。

感覚的にはブロックの下の方が正しいように思えます。何故上なのだろう?

package main

import "fmt"

func main() {
LBL1:
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			if i == 1 { break LBL1 }
			fmt.Println(i, j)
		}
	}
//LBL2:                                        // ここを指定するとエラー
	fmt.Println("End.")
}

Go言語 - WALKでGUI - MessageBox

MessageBoxの使用例。

ボタンクリックでMessageBoxを作成し表示させています

4番目の引数メッセージボックススタイル指定しています。また各々のスタイルボタン種類で戻り値が変わるので、戻り値に応じた処理が必要になります


f:id:hake:20150906102629j:image

続きを読む

2015-09-05(Sat)

Go言語 - WALKでGUI - 単独起動する実行ファイルの作成

WindowsでWALKライブラリを使用したGUIアプリケーションの起動には、マニフェストファイルを同じ場所に置いておく必要がありましたが、rsrcというツールマニフェストファイル(とアイコンファイル)を実行ファイル内に取り込むことで単独起動するファイル作成する方法がわかったのでメモです。

入手先

go get github.com/akavel/rsrc

インストールし、rsrcフォルダに移動して、rsrc.goコンパイルする。

作成されたrsrc.exeパスの通った場所に移動する。


sysoファイル作成

マニフェストファイル(とアイコンファイル)を用意して、以下を実行します

rsrc -manifest APP.exe.manifest -ico ICON.ico -o APP.syso

goファイルコンパイル

アプリケーション名をつけたフォルダに、goファイルとsysoファイルを置いてコンパイルする。

【注意】ソースファイル名を指定しないでコンパイルする必要があります

  go build -ldflags="-H windowsgui"

Go言語 - WALKでGUI - FileDialog

FileDialogの使用例。

ボタンクリックでFileDialogを作成し表示させています

walk.FileDialog構造体を作成して、ShowOpenメソッドで表示させますダイアログキャンセルで閉じられた場合には戻り値のokがfalseになり、trueの場合はFilePathフィールドからファイルパスを取得します

特定の拡張子ファイルのみ表示させる場合には、Filterフィールドに設定します。例ではexeファイルのみと全ファイルを選択できる様にしています


f:id:hake:20150905174705j:image:medium

続きを読む

2015-09-04(Fri)

Go言語 - WALKでGUI - Menu

Menuの使用例。以下の構造のメニューを作成しました。

  File               Else
  ├ Open            └ About
  ├ SubMenu
  |  └ SubItem1
  └ Exit

MainWinsdowのMenuItemsフィールドにMenuウィジェット階層的に置いていき末端の項目にはActionウィジェットを置いています

各ActionのOnTriggeredフィールドには処理のメソッド名を記載しますが、Exitメニュ項目のみ直接関数記載しています

f:id:hake:20150904191958j:image

続きを読む

2015-09-03(Thu)

Go言語 - WALKでGUI - RadioButton

RadioButtonの使用例。

起動時にRadioButtonを選択してある状態にする方法がわからない。。。

RadioButtunをRadioButtonGroupBoxの中に配置することで、そのグループ内で排他選択ができるようになります。各RadioButtonウィジェットから、そのボタンが選択されているか情報が取得できない様なので、MyMainWindow構造体の中にフィールドを追加して、RadioButtonのクリックイベントでフィールドの値にRadioButtonのValuefフィールドの値を設定する様にしています。このときValue()メソッドで返されるのがinterface{}型の為、型アサーションでint型に変換して代入しました。

f:id:hake:20150903185050j:image

続きを読む

2015-09-02(Wed)

Go言語 - WALKでGUI - CheckBox

CheckBoxの使用例。

CheckBoxも状態を保持するので、MyMainWindow構造体に変数を追加し、実体としてアサインします。

つのCheckBoxをGroupBoxの下に配置して、LayoutフィールドをHBoxにすることでCheckBoxを水平に並べています。また、Check1のCheckedフィールドをtrueにして初期状態でチェックされている状態にしています。

つのCheckBoxともOnCheckedChangedイベントで状態が変わったことを表示させるようにしています。

ボタンクリックイベント処理で使用している定数walk.CheckCheckedは、ライブラリのcheckbox.go定義されているものを使用しました。

f:id:hake:20150902190248j:image

続きを読む

2015-09-01(Tue)

Go言語 - 省略書式の変数宣言とスコープで悩んだ点(Go1.5)

以下のプログラムでは、forブロックの中で関数hoge戻り値を取得しています。

このとき変数errが初めて登場したため'='ではなく':='を使用したのですが、こうすると変数aもforブロック内のローカル変数と判断されてしまいます。このため、ループ条件で使用している(ローカル変数ではない)aの値が変更されなくなって、forブロックから抜け出すことができません。

package main

import "fmt"

func hoge() (string, error){
    return "bar", nil
} 

func main() {
    var a string = "foo"

    fmt.Println(a)           //-> foo
    for a == "foo" {         // 無限ループになる(ここのaが変更されない)
        a, err := hoge()
        fmt.Println(a, err)  //-> bar <nil> // aには関数の戻り値が代入されている
    }
    fmt.Println(a)
}

対処

errを事前に宣言しておき、関数戻り値は'='で受ける。

    var err error           // 予め宣言しておく
    for a == "foo" {
        a, err = hoge()     //  '='を使用
        fmt.Println(a, err)
    }

Go言語 - WALKでGUI - ComboBox

ComboBox(プルダウンメニュー)の使用例。

ComboBoxは状態を保持するので、MyMainWindow構造体に変数を追加し、実体としてアサインします。

Modelフィールドで表示する項目を、CurrentIndexフィールドで初期値を設定しています。

選択項目を変更すると、OnCurrentIndexChangedイベントが発生するので、選択したTextを表示させています。また、ボタンクリック現在選択されているIndex値とTextを表示した後、メニュー最初の値(Index = 0)に設定しなおす動作を行います。


package main

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

import (
	"fmt"
	"os"
)

type MyMainWindow struct {
	*walk.MainWindow
	combo  *walk.ComboBox
	edit   *walk.TextEdit
}

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

	var menuItems = []string {    // ComboBox項目リスト
		"One",
		"Two",
		"Three",
		"Four",
		"Five",
	}

	MW := MainWindow{
		AssignTo: &mw.MainWindow,
		Title: "ComboBoxテスト",
		MinSize: Size {150, 200},
		Size   : Size {300, 400},
		Layout: VBox {},
		Children: []Widget {
			ComboBox {
				AssignTo: &mw.combo,
				Model: menuItems,
				CurrentIndex: 2,        // 初期値
				OnCurrentIndexChanged: mw.comboChanged,
			},
			TextEdit {
				AssignTo: &mw.edit,
			},
			PushButton {
				Text: "Push",
				OnClicked: mw.pbClicked,
			},
		},
	}

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

}

// ComboBox 変更時イベント処理
func (mw *MyMainWindow) comboChanged() {
	s := "Event: " + mw.combo.Text() + " slected.\r\n"
	mw.edit.AppendText(s)
}

// PushButtonクリック時イベント処理
func (mw *MyMainWindow) pbClicked() {
	s := fmt.Sprintf("CurIdx: %d,  CurText: %s\r\n",
	                     mw.combo.CurrentIndex(),
	                     mw.combo.Text() )
	mw.edit.AppendText(s)

	mw.edit.AppendText("Set Index 0\r\n")
	mw.combo.SetCurrentIndex(0)             // 一番上の項目を設定

}