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 | 10 |

2016-01-31(Sun)

Go言語 - ファイルの存在確認

Packagesドキュメントに、そのものの機能が見つからなかったのでメモ

package main

import (
	"fmt"
	"os"
)

func Exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

func main() {
	if b := Exists("sample.txt"); b {
		fmt.Println("file exist!!")
	} else {
		fmt.Println("file not exist!!")
	}
}

Go言語 - データベースを使用する - sqlite3

go言語でsqlite3を使用してみる。

Windows 64bitで下記の方法だと、コンパイル時に何故かgcc要求されますコンパイルに通常よりも時間がかかるのでgccを利用した何かを行っている? なお作成されたexeファイルの実行はgcc環境がなくてもOKでした。

入手先


データベース作成データの追加

package main

import (
	"os"
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
)

func main(){
	
	var dbfile string = "./test.db"

	os.Remove( dbfile )

//	db, err := sql.Open("sqlite3", ":memory:")
	db, err := sql.Open("sqlite3", dbfile)
	if err != nil { panic(err) }

	_, err = db.Exec( `CREATE TABLE "world" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "country" VARCHAR(255), "capital" VARCHAR(255))` )
	if err != nil { panic(err) }

	_, err = db.Exec(
			`INSERT INTO "world" ("country", "capital") VALUES (?, ?) `,
			 "日本",
			 "東京",
			)
	if err != nil { panic(err) }


	stmt, err := db.Prepare( `INSERT INTO "world" ("country", "capital") VALUES (?, ?) ` )
	if err != nil { panic(err) }

	if _, err = stmt.Exec("アメリカ", "ワシントンD.C."); err != nil { panic(err) }
	if _, err = stmt.Exec("ロシア", "モスクワ"); err != nil { panic(err) }
	if _, err = stmt.Exec("イギリス", "ロンドン"); err != nil { panic(err) }
	if _, err = stmt.Exec("オーストラリア", "シドニー"); err != nil { panic(err) }
	stmt.Close()

	db.Close()
}

コマンドプロンプトから確認
C:\work\go\sqlite>sqlite3 test.db
SQLite version 3.10.2 2016-01-20 15:27:19
Enter ".help" for usage hints.
sqlite> select * from world;
1|日本|東京
2|アメリカ|ワシントンD.C.
3|ロシア|モスクワ
4|イギリス|ロンドン
5|オーストラリア|シドニー

データの表示

package main

import (
	"fmt"
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
)

func main(){
	var id int
	var country string
	var capital string

	db, err := sql.Open("sqlite3", "./test.db")
	if err != nil { panic(err) }

	rows, err := db.Query( `SELECT * FROM world` )
	if err != nil { panic(err) }

	for rows.Next() {
		err = rows.Scan(&id, &country, &capital)
		if err != nil { panic(err) }
		fmt.Println(id, " ", country, " ", capital)
	}

	db.Close()
}

データ更新

package main

import (
	"fmt"
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
)

func main(){
	
	var dbfile string = "./test.db"

	db, err := sql.Open("sqlite3", dbfile)
	if err != nil { panic(err) }

	stmt, err := db.Prepare( `UPDATE "world" SET capital=? WHERE country=?` )
	if err != nil { panic(err) }

	res, err := stmt.Exec("キャンベラ", "オーストラリア")
	if err != nil { panic(err) }

	affect, err := res.RowsAffected()
	if err != nil { panic(err) }

	fmt.Println(affect, "個のデータを更新しました。")
	stmt.Close()

	db.Close()
}

2015-12-05(Sat)

Go言語 - 式の構文解析 - 演算子順位法

再起下降法と比較してのメリットは、演算子の優先度に応じてparse関数作成する必要がなく、演算子の優先順位・結合方向をデータとして与えるだけで良いということ。

ident1 op1 ident2 op2 ident3 op3 ……

上記のような並びの式の場合、演算子op1とop2の優先順位と結合方向を比較して、ident2がident1とペアのノードとなるか、ident3以降とペアのノードとなるかを判断する。


構文

  expr    = primary { op primary }      # { }は0回以上の繰り返し
  primary = ident | '(' expr ')'
  op      = '=' | '+' | '-' | '*' | '/' | '^'
  ident   = 'A' … 'Z' 'a' … 'z'

primaryの中のカッコの処理は、通常の再起下降法で処理。並びの演算子の比較とノードの作成は、makeNode()関数実施している。


ソース

package main

import (
	"fmt"
	"os"
)

type Lexer struct{
	buf   string
	size  int
	pos   int
}
func NewLexer(s string) *Lexer {
	l := new(Lexer)
	l.buf = s
	l.size = len(l.buf)
	l.pos = 0
	return l
}
func (self *Lexer) Get() (byte, int) {
	if self.pos >= self.size {
		return 0, self.pos
	} else {
		idx  := self.pos
		char := self.buf[idx]
		self.pos += 1
		return char, idx
	}
}
func (self *Lexer) Peek(offset int) (byte, int) {
	if self.pos + offset >= self.size {
		return 0, self.pos + offset
	} else {
		c := self.buf[self.pos + offset]
		return c, self.pos + offset
	}
}


type NodeType uint32
const (
	NodeIdent    NodeType = iota + 128 // 識別子
	NodeOp                             // 演算子
)


type Node struct {
	Type    NodeType
	Value   byte
	Left    *Node
	Right   *Node
}
func NewNode(t NodeType, char byte) *Node {
	n := new(Node)
	n.Type = t
	n.Value = char
	return n
}


// 引数のNodeを演算子の前置記法で表示
func (self *Node)String() string {
	switch self.Type {
	case NodeIdent:  return string(self.Value)
	case NodeOp:
		s := "(" + string(self.Value)+ " "
		s += self.Left.String() + " "
		s += self.Right.String() + ") "
		return s
	default: return "表示できない要素があります。"
	}
}

// 演算子情報
type OpInfo struct {
	Rank int    // 順位
	Dir  bool   // 結合方向 左結合ならば true
}

//
//  構文
//
//    expr    = primary { op primary }
//
//    primary = ident | '(' expr ')'
//
//    op      = '=' | '+' | '-' | '*' | '/' | '^'
//
//    ident   = 'A' … 'Z' 'a' … 'z'
//
//
type Parser struct{
	lx   *Lexer
	tbl  map[byte] OpInfo
}
func NewParser(s string) *Parser {
	p := new(Parser)
	p.lx = NewLexer(s)
	p.tbl = map[byte]OpInfo{
			'=': {0, false}, // 順位低 右結合
			'+': {1, true }, //        左結合
			'-': {1, true },
			'*': {2, true },
			'/': {2, true },
			'^': {3, false}, // 順位高
			}
	return p
}
func (self *Parser) Parse() *Node {
	leftNode := self.primary()
	c, _ := self.lx.Peek(0)
	b, _ := self.isOp(c)
	for (c != 0) && b {
		leftNode = self.makeNode(leftNode)
		c, _ = self.lx.Peek(0)
		b, _ = self.isOp(c)
	}
	return leftNode
}
func (self *Parser) makeNode(leftIdentNode *Node) *Node {
	curOpNode, curOpInfo := self.readOp()
	rightIdentNode := self.primary()
	c, _ := self.lx.Peek(0)
	b, _ := self.isOp(c)
	for (c != 0) && b {
		nextOpInfo := self.peekOp(0)
		if self.compareOp(curOpInfo, nextOpInfo) {
			rightIdentNode = self.makeNode(rightIdentNode)

		} else {
			break
		}
		c, _ = self.lx.Peek(0)
		b, _ = self.isOp(c)
	}
	curOpNode.Left  = leftIdentNode
	curOpNode.Right = rightIdentNode
	return curOpNode
}
// 次の演算子が優先の場合 true
//   現演算子:左結合  &  現 <  次
//   現演算子:右結合  &  現 <= 次
func (self *Parser) compareOp(cur OpInfo, next OpInfo) bool {
	if (cur.Dir == true) && (cur.Rank < next.Rank ){
		return true
	} else if (cur.Dir == false) && (cur.Rank <= next.Rank) {
		return true
	}
	return false
}

//
// primary = ident | '(' expr ')'
//
func (self *Parser) primary() *Node {
	var node *Node
	char, idx := self.lx.Get()
	switch {
	case char == '(':
		node = self.Parse()
		if char, idx = self.lx.Get(); char != ')' {
			ErrorP("文法エラー0( ')'ではありません)", char, idx)
		}
	case self.isIdent(char):
		node = NewNode(NodeIdent, char)
	default:
		ErrorP("文法エラー1(変数名ではありません)", char, idx)
	}
	return node
}
func (self *Parser) peekOp(i int) OpInfo {
	char, idx := self.lx.Peek(i)
	b, info := self.isOp(char)
	if b == false {
		ErrorP("文法エラー2(演算子ではありません)", char, idx)
	}
	return info
}
func (self *Parser) readOp() (*Node, OpInfo) {
	char, idx := self.lx.Get()
	b, info := self.isOp(char)
	if b == false {
		ErrorP("文法エラー3(演算子ではありません)", char, idx)
	}
	return NewNode(NodeOp, char), info
}
func (self *Parser) readIdent() *Node {
	char, idx := self.lx.Get()
	if self.isIdent(char) == false {
		ErrorP("文法エラー4(識別子ではありません)", char, idx)
	}
	return NewNode(NodeIdent, char)
}

// 演算子であるかチェック
func (self *Parser) isOp(char byte) (bool, OpInfo) {
	if info, b := self.tbl[char]; b {
		return true, info
	}
	return false, OpInfo{0, false}
}
// 変数(識別子)であるかチェック
func  (self *Parser)isIdent(char byte) bool {
	if ( char >= 'A' && char <= 'Z')||( char >= 'a' && char <= 'z') {
		return true
	}
	return false
}



func ErrorP(msg string, char byte, idx int) {
	var s string
	if char == 0 {
		s = "EOL"
	} else {
		s = string(char)
	}
	fmt.Println(msg, "char:", s, ", pos:", idx)
	os.Exit(1)
}


func main() {
	p := NewParser("a=b=c+(d=e*(f+g))")
	n := p.Parse()
	fmt.Print(n)
}

実行結果

(= a (= b (+ c (= d (* e (+ f g) ) ) ) ) )

2015-11-29(Sun)

Go言語 - 構造体の埋め込みをクラスの継承っぽく使用

埋め込んだ構造体の初期化を、その構造体の初期化関数初期化するにはどうすれば良いのかわからなかったけれども、レシーバ.埋め込んだ構造体名.関数名()で埋め込んだ構造体に定義した関数を呼べるみたいなので初期化関数Super()を作ってテスト。


ただし初期化関数から同じ構造体の他の関数を呼ぶと、埋め込んだ構造体側の関数が呼ばれるらしい


package main
import "fmt"

type A struct {
	x int
}
func NewA(x int) *A {
	a := new(A)
	a.Super(x)    // メンバ変数を初期化
	return a
}
func (self *A)Super(x int){
	self.x = x
}
func (self *A)Print(){
	fmt.Println("x =", self.x)
}

type B struct {      // BにAを埋め込む(継承っぽい)
	A
	y int
}
func NewB(x int, y int) *B {
	b := new(B)
	b.Super(x, y)    // メンバ変数を初期化
	return b
}
func (self *B)Super(x int, y int){
	self.A.Super(x)            // 埋め込んだ構造体Aの関数Super()を呼ぶ
	self.y = y
}
func (self *B)Print(){
	self.A.Print()             // 埋め込んだ構造体Aの関数Print()を呼ぶ
	fmt.Println("y =", self.y)
}


func main() {
	a := NewA(1) //=> x = 1
	a.Print()
	b := NewB(2,3)
	b.Print()    //=> x = 2
	             //=> y = 3
}