break, continue, goto, returnで抜ける
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
return err
}
codeUsing(f, d)
// Cのwhileに相当する形式
for condition { }
// Cのfor(;;)に相当する形式
for { }
// range
var m map[string]int
sum := 0
for _, value := range m { // キーは使われません
sum += value
}
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:len(buf)]
}
return
}
returnするときの処理を予約
// Contentsは、ファイルの内容を文字列として返します。
func Contents(filename string) (string, os.Error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close() // f.Closeは、完了時に実行される
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
rresult = append(result, buf[0:n]...) // appendについては後述します。
if err != nil {
if err == os.EOF {
break
}
return "", err // ここでリターンしたときに、fはクローズされる
}
}
return string(result), nil // ここでリターンしたときに、fはクローズされる
}
new
はゼロ値で埋めたオブジェクトのポインタを返すmake
はスライス, マップ, チャネルだけに使える
// コンストラクタの例
return &File{fd, name, nil, 0}
// makeの例, 型, 長さ, キャパシティ
make([]int, 10, 100)
http://jxck.hatenablog.com/entry/golang-slice-internals
- 配列は関数に渡すと値渡し
- 配列の長さは変更できない
- スライスは配列をラップしている
- スライスは可変長配列のように使える
- スライスは参照型
- なので関数に渡しても参照が渡る
arr := []int{1, 2, 3, 4}
arr := make([]int, 4)
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5 // index out of range
arr = append(arr, 5)
arr = append(arr, 6)
- 宣言時の
arr
はどちら長さ4の配列への参照 - そのままでは
arr[4]
へ代入することはできない append
は倍の長さの配列を確保してそこにコピーする- appendした後の
cap(arr)
はキャパシティ8 - なので, たくさん詰める時はmakeするときにcapを指定しておくと良い
arr := make([]int, 0, 5)
- makeの第二引数が0なのは, 詰める値を初期化しないため
- appendするのか添字アクセスするか変わってくる
var arr []int
はlen=0, cap=0
// スライス連結の例
func Merge3(a, b []int) []int {
return append(a, b...)
}
func del(a []int, i int) []int {
copy(a[i:], a[i+1:])
a = a[:len(a)-1]
return a
}
func main() {
a := []int{1, 2, 3, 4, 5}
a = del(a, 2)
log.Println(a, len(a), cap(a)) // [1 2 4 5] 4 5
}
// []int *
// |
// [5]int [1, 2, 4, 5, 5]
log.Println(a[:cap(a)])
- delでスライスから削除しても実体の配列には値が残ってGCされないケースがある
var zero int // ゼロ値
func del(a []int, i int) []int {
copy(a[i:], a[i+1:])
a[len(a)-1] = zero // ゼロ値, nil の代入
a = a[:len(a)-1]
return a
}
- ちゃんとゼロ値を代入しましょう
var timeZone = map[string] int {
"UTC": 0*60*60,
"EST": -5*60*60,
"CST": -6*60*60,
"MST": -7*60*60,
"PST": -8*60*60,
}
- 存在しないキーが与えられたら, valueのゼロ値が返る
func offset(tz string) int {
if seconds, ok := timeZone[tz]; ok {
return seconds
}
log.Println("unknown time zone:", tz)
return 0
}
- ゼロ値とキーの存在を区別したいパターンは上記
fmt.Printf("Hello %d\n", 23)
fmt.Fprint(os.Stdout, "Hello ", 23, "\n")
fmt.Println("Hello", 23)
fmt.Println(fmt.Sprint("Hello ", 23))
%v
が万能?で便利なフォーマット指定%+v
で&{a:7 b:-2.35 c:abc def}
のように構造体のフィールド名が%#v
で&main.T{a:7, b:-2.35, c:"abc\tdef"}
のように型情報も出力される%T
で型情報を出力
func (t *T) String() string {
return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}
String() string
のメソッドを定義するとデフォルトフォーマットを定義