これをやる
ポインタ
package main import "fmt" func main() { i := 10; p := &i fmt.Println(p) // ポインタ fmt.Println(*p) // 値 *p = 20 // ポインタ経由での値変更 fmt.Println(i) v := 20 i = v fmt.Println(&i) // 代入しても参照先は変わらない fmt.Println(&v) // が、vとiの参照先は別 }
Javaの感覚で捉えてしまうと最後のiは参照先が変わりそうだが変わらなかった。 基本的には
&
で参照先アドレスを取得*
で参照先アドレスから値を取得
ということで良さそうだが。 ポインタを直接操作することはできない。(Cでポインタにintegerの幅だけずらした値を足して配列の次の値をとる的なのがあった気がするがそういうのか?)
後ポインタに別の値のポインタを代入とかもだめ。
struct
フィールドの集合
structsへアクセスするポインタ
structへのアクセスは、変数にドット繋ぎでもできるし、ポインタにドット繋ぎでも可能。
package main import "fmt" type Structure struct { X int Y int } func main() { v := Structure{1, 2} // 初期化 v.X = 100 fmt.Println(v) // {100 2} p := &v p.X = 1000 // ポインタ.フィールド、で直接フィールドを参照できる fmt.Println(v) // {1000 2} (*p).X = 10000 // これでもいける fmt.Println(v) // {10000 2} }
これポインタ経由でのアクセスかどうかに差ないのかな? ちょっと気持ち悪い気がするけどそもそもポインタを使いたくなるケースが見えてないのでなんとも言えない。
ArraysとSlices
変数の型としては同じものを指しているのかなと思ったが、
Slices are like references to arrays
とのこと。 ので、ArrayからSliceを取得してSliceの値をいじると元のArrayの値も変更される。
sliceのlengthとcapacity
length
sliceの要素数
capacity
sliceの最初の要素からsliceが参照してるarrayの末尾の要素までの要素数
capacityの範囲でsliceの要素は元のarrayに戻せる。
package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} s = s[2:4] fmt.Println(s) // 5, 7 fmt.Printf("%d %d \n",len(s), cap(s)) // 2, 4 s = s[0:] fmt.Println(s) // 5, 7(これはcapacityの範囲ではなくlengthの範囲でのsliceになる) fmt.Printf("%d %d \n",len(s), cap(s)) // 2, 4 s = s[0:4] fmt.Println(s) // 5, 7, 11, 13 fmt.Printf("%d %d \n",len(s), cap(s)) // 4, 4 }
built-in関数make
a := make([]int, 3) // len(a) = 3, cap(a) = 3 b := make([]int, 3, 5) // len(a) = 3, cap(a) = 5
rangeによるイテレーション
func main() { values := []int{1,2,3} for index, value := range values { fmt.Println("index:%d, value:%d", index, value) } }
rangeでmapとsliceのイテレーションを提供する。sliceの場合indexとvalue。
Exercise: Slices
package main import "golang.org/x/tour/pic" func Pic(dx, dy int) [][]uint8 { vals := make([][]uint8, dy) for i,_ := range vals { vals[i] = make([]uint8, dx) for j,_ := range vals[i] { vals[i][j] = uint8((int(i) + int(j))/2) } } return vals } func main() { pic.Show(Pic) }
グラデーションになった。
Map
rubyのhashみたいな感じ。
package main import "fmt" type Test struct { test string } type Key struct { test string } var key1 = Key{"key1"} var key2 = Key{"key2"} var m = map[Key]Test{ key1: Test{"test1"}, key2: Test{"test2"}, } func main() { fmt.Println(m) fmt.Println(m[key1]) }
これでもいい。
var m = map[Key]Test{ key1: {"test1"}, key2: {"test2"}, }
Mapの操作
package main import "fmt" func main() { m := make(map[string]string) m["key1"] = "value1" val := m["key1"] fmt.Println(val) val1, ok1 := m["key1"] fmt.Printf("val:%d, ok:%s\n" , val1, ok1) val2, ok2 := m["key2"] fmt.Printf("val:%d, ok:%s\n" , val2, ok2) }
2つ目の戻り値でkeyに対応する値の有無を取得できる。
Exercise: Maps
package main import ( "golang.org/x/tour/wc" "strings" ) func WordCount(s string) map[string]int { words := strings.Fields(s) counter := make(map[string]int) for _, value := range words { count, ok := counter[value] if ok { counter[value] = count + 1 } else { counter[value] = 1 } } return counter } func main() { wc.Test(WordCount) }
でもこのケースだとmapのvalueは初期化時に0でいいので
package main import ( "golang.org/x/tour/wc" "strings" ) func WordCount(s string) map[string]int { words := strings.Fields(s) counter := make(map[string]int) for _, value := range words { counter[value]++ } return counter } func main() { wc.Test(WordCount) }
でいい。
Exercise: Fibonacci closure
package main import "fmt" // fibonacci is a function that returns // a function that returns an int. func fibonacci() func() int { index := 0 first := 0 second := 1 return func() int { index++ switch index { case 1: return 0 case 2: return 1 } now := first + second first = second second = now return now } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }
ここにシュッとした回答がいっぱいある。