SlideShare a Scribd company logo
Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)
Revised v4Presenter
プログラミング言語Go
鵜飼文敏 / Google Software Engineer
今日の内容
godentaku - Goで作った電卓
入出力の基本
sliceの使い方
型システム: struct, pointer, interface
goパッケージ
ローカル・サードパーティ
使い方・作り方
Go言語とは?
新しいシステムプログラミング言語
Googleが設計・開発
Rob Pike, Ken Thompson, Robert Griesemer,
Russ Cox, Ian Lance Taylerなど
2009/11/10にオープンソースとして公開
http://golang.org
コントリビュータ: 125名 (2010/09)
Go言語の特徴
静的型付け・型安全
ダックタイピング
短いコンパイル時間
大規模プログラミング可能
ネットワーキング
マルチコア
主流プログラミング言語
C++, Java
ライトウェイト言語
Python, Rubyなど
What's new?
DevFest (2010/3)から
complex型
x := m[k] がpanicしなくなった。
s[0:n] が s[:n]に
panic(), recover()
goinstallコマンド
gomakeコマンド ($GOOS, $GOARCH, ...)
goprofコマンド
Go dashboard
new package
crypto/ripemd160, hash/crc64, crypto/rand, utf16, nntp, mime/multipart, html, net/textp
roto, net/dict, crypto/ocsp, runtime/pprof, http/pprof, cmath, rpc/jsonrpc,
go/typechecker
once -> sync.Once()
The Go Playground
今日のお題:電卓
$ ./godentaku
>1+2*3
7
>y=x*x + (a+b)*x + a*b
(((x * x) + ((a + b) * x)) + (a * b))
>a=1
1
>b=2
2
>y
(((x * x) + (3 * x)) + 2)
>x=5
5
>y
42
godentaku
仕様
式を入力して、それを評価して出力
四則演算
変数
言語の基本機能で実装
パッケージをあまり使わない
(fmt, os, bufioのみ)
godentaku
入力
標準入力から一行づつバイト列を読み取る
式を解析
バイト列を抽象構文木に変換
式を評価
抽象構文木を解釈・実行
結果を出力
結果を文字列にして標準出力に
繰り返す
入力: bufio
http://golang.org/pkg/bufio/#Reader.ReadBytes
func (*Reader) ReadBytes
func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error)
ReadBytes reads until the first occurrence of delim in the input, returning a string containing the data up to and
including the delimiter. If ReadBytes encounters an error before finding a delimiter, it returns the data read
before the error and the error itself (often os.EOF). ReadBytes returns err != nil if and only if line does not end in
delim.
import ("bufio"; "os")
in := bufio.NewReader(os.Stdin)
line, err := in.ReadBytes('n')
if err != nil { ... }
出力: fmt
http://golang.org/pkg/fmt/#Printf
func Printf
func Printf(format string, a ...interface{}) (n int, errno os.Error)
Printf formats according to a format specifier and writes to standard output. It returns the number of bytes written and
any write error encountered.
import "fmt"
fmt.Printf("> ")
fmt.Printf("%d", i)
fmt.Printf("%#v", v)
コンパイル&実行
% cat main.go
package main
import ("bufio"; "fmt"; "os")
func main() {
in := bufio.NewReader(os.Stdin)
for {
line, err := in.ReadBytes('n')
if err != nil { break }
fmt.Println(string(line))
}
}
% 6g main.go # 8g main.go
% 6l main.6 # 8l main.8
% ./6.out # ./8.out
Read-eval-print loop
package main
import ("bufio"; "fmt"; "os")
func readEvalPrint(in *bufio.Reader, env *Env) os.Error
func main() {
in := bufio.NewReader(os.Stdin)
env := NewEnv() // for variable table
for {
err := readEvalPrint(in, env)
if err != nil { break }
}
}
Read-eval-print loop
func readEvalPrint(in *bufio.Reader, env *Env) os.Error {
fmt.Printf("> ")
line, err := in.ReadBytes('n')
if err != nil { return err }
ast, nbuf := Read(line)
v := Eval(ast, env)
fmt.Println(Print(v, env))
return nil
}
Read: getNum
func getNum(buf []byte) (n int, nbuf []byte) {
n := digitVal(buf[0])
nbuf = buf[1:]
for len(nbuf) > 0 {
if d := digitVal(nbuf[0]); d >= 0 {
n = n * 10 + d
} else { break }
nbuf = nbuf[1:]
}
return n, nbuf
}
func digitVal(b byte) int {
if b >= '0' && b <= '9' {
return int(b - '0') // int型に変換
} else { return -1 }
}
slice
sliceは配列につかうポインタ
Read: getSymbol
func getSymbol(buf []byte) (sym string, nbuf []byte) {
var i int
for i = 0; i < len(buf); i++ {
if !isAlpha(buf[i]) && !isDigit(buf[i]) {
break
}
}
return string(buf[0:i]), buf[i:]
}
抽象構文木
再帰降下パーザ
// stmt := expr | sym '=' expr
func parseStatement(b []byte) (stmt Ast, n []byte)
// expr := ['+'|'-'] term { ['+'|'-'] term }
func parseExpression(b []byte) (expr Ast, n []byte)
// term := factor { ['*'|'/'] factor }
func parseTerm(b []byte) (term Ast, n []byte)
// factor := num | symbol | '(' expr ')'
func parseFactor(b []byte) (factor Ast, n []byte)
interface: Ast
type Ast interface {
String() string
Eval(env* Env) Ast
}
Ast型の変数に代入できるのは、これらのメソッドが定義されて
いる型のオブジェクト
Astにいれて使う型はこれらのメソッドを定義
Astを使うほうは、これらのメソッドが利用可能
named type: Num
type Num int
func (n Num) String() string {
return fmt.Sprintf("%d", int(n))
}
func (n Num) Eval(env *Env) Ast { return n }
func getNum(b []byte) (num Num, nbuf []byte) {
...
return Num(n), nbuf
}
NumはAst型
named type: Symbol
type Symbol string
func (s Symbol) String() string {
return string(s)
}
func (s Symbol) Eval(env *Env) Ast { ... }
SymbolもAst型
map: variable table
type Env struct { Var map[string]Ast; .. }
func NewEnv() *Env {
env := new(Env)
env.Var = make(map[string]Ast)
return env
}
func Set(env* Env, key string, n int) {
env.Var[key] = Num(n)
}
func envValue(env* Env, key string) (n int, ok bool) {
if v, found := env.Var[key]; found {
..
}
return 0, false
}
structとポインタ
type Point struct { x, y int }
type Rect struct { min, max Point }
type Rect2 struct { min, max *Point }
BinOp
type Ast interface { .. }
type BinOp struct { Op byte; Left, Right Ast }
func (b BinOp) String() string {..}
func (b BinOp) Eval(env *Env) Ast { .. }
func parseExpression(b []byte) (expr Ast, n []byte) {
expr, n = parseTerm(b)
for n[0] == '+' || n[0] == '-' {
op := n[0]; var term Ast
term, n = parseTerm(n[1:])
expr = BinOp{Op: op, Left:expr, Right:term}
}
return expr, n
}
BinOpもAst型
interface: memory layout
interface type-switch
func parseStatement(b []byte) (stmt Ast, n []byte) {
stmt, n = parseExpression(b)
if n[0] == '=' {
if sym, ok := stmt.(Symbol); ok {
var expr Ast
expr, n = parseExpression(n[1:])
stmt = AssignOp{Var:sym, Expr:expr}
} else { /* 例外処理 */ }
}
return stmt, n
}
例外処理
func readEvalPrint(in *bufio.Reader, env *Env) os.Error {
defer func() { if x := recover(); x != nil { ... } }()
.. Read(line) ..
}
func Read(b []byte) (ast Ast, n[]byte) {
return parseStatement(b)
}
func parseStatement(b []byte) (stmt Ast, n []byte) {
...
if sym, ok := stmt.(Symbol); ok { ..
} else {
panic("lvalue is not symbol:" + stmt.String());
}
}
いままでのまとめ
入出力
bufio
fmt
型システム
int, string, ..
slice
map
struct
ポインタ
interface
packageにする
1. ファイルを分割する
メインのファイル (main.go)
パッケージのファイル (godentaku.go)
2. メインのファイル
import に "./godentaku"
godentaku.Read(line)
3. パッケージのファイル
package godentaku
大文字ではじまるシンボルがパブリック
packageのビルド
% 6g godentaku.go
% 6g main.go # main.goとgodentaku.6を読む
% ls
godentaku.6 godentaku.go
main.6 main.go
% 6l main.6
% ./6.out
packageディレクトリ
% mkdir godentaku; mv godentaku.* godentaku/; cd godentaku
% cat > Makefile
include $(GOROOT)/src/Make.inc
TARG=godentaku # importでつかうパッケージパス
GOFILES=
godentaku.go
include $(GOROOT)/src/Make.pkg
% gomake # コンパイルとリンク
% gomake install # -> ${GOROOT}/pkg/${GOOS}_${GOARCH}/${TARG}.a
packageの公開
標準packageにコントリビュート
codereview
http://golang.org/doc/contribute.html
サードパーティpackageとして公開
http://godashboard.appspot.com/package
サードパーティpackageの利用
インストール
% goinstall goprotobuf.googlecode.com/hg/proto
利用する時
import "goprotobuf.googlecode.com/hg/proto"
data, err := proto.Marshal(obj)
googlecode - project hosting
googlecode - createProject
Mercurial
https://yourproj.googlecode.com/hg
hgrc
% cat .hg/hgrc
[paths]
default = https://yourproj.googlecode.com/hg/
[ui]
username = Your Name <foo@example.com>
[auth]
googlecode.prefix = yourproj.googlecode.com/hg/
gogolecode.username = foo@example.com
googlecode.password = XXXXX
googlecode.schemes = https
publish package
1. プロジェクトの作成
2. hg clone
3. hgrcの編集
4. ファイルの追加
hg add
Makefileの編集
TARGを import path
5. hg commit
6. hg push
本日のまとめ
Go言語を使って
入出力の基本
型システムの基本
packageの使い方・作り方
googlecode project hostingで公開
今日やらなかったこと
並行処理: goroutineとchannel
Iota: enum的なもの
goツール
godoc, gofmt, gotest, goyacc など
cgo: Cコードを呼ぶgoパッケージの作成
標準パッケージの使い方
などなど
May the Source be with You

More Related Content

Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)