for i := 0; i < 10; i++ {
sum += i
}
初期化と後処理は省略可
sum := 1
for ; sum < 1000; {
sum += sum
}
セミコロンも省略可(while文相当)
sum := 1
for sum < 1000 {
sum += sum
}
条件を省略すれば無限ループになる
for {
}
i := 5
if i < 10 {
fmt.Printf("i: %d\n", i)
}
条件の前に一文書ける
変数のスコープはifブロックになる(elseでも使える)
j := 5
if i := 10; j < i {
fmt.Printf("i, j: %d, %d\n", i, j)
} else {
fmt.Printf("i: %d\n", i)
}
- breakがいらない(書かなくてもbreakする)
- fallthroughを書くとbreakしない
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.", os)
}
- 条件を省略することもできる
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
- 関数をスタックしておける
- deferした関数は呼び出し元がreturn下タイミングで呼ばれる
- 複数deferしている場合LIFO(last-in-first-out)になる
// counting
// done
// 9
// 8
// 7...
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
func main() {
i := 42
p := &i // iのポインタを引き出してpに代入する
fmt.Println(*p) // ポインタ経由でiを読み出す
*p = 21 // ポインタ経由でiの値を書き換える
fmt.Println(i) // iの値が変わっている
}
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X) // 4
fmt.Println(v.Y) // 2
}
v := Vertex{Y:1, X:2}
// 名前をつけると初期値を省略できる
v2 := Vertex{X:2}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v) // {1000000000 1}
}
// Arrays
var a [2]string
a[0] = "Hello"
a[1] = "World"
primes := [6]int{2, 3, 5, 7, 11, 13}
// slices {3, 5, 7}
// Sliceは配列への参照なので、変更は同じ参照すべてに反映される
var s []int = primes[1:4]
q := []int{2, 3, 5, 7, 11, 13}
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
下記のSliceはすべて同じ意味
var a [10]int
a[0:10]
a[:10]
a[0:]
a[:]
スライスの長さ(要素数): length 容量: capacity
s := []int{2, 3, 5, 7, 11, 13}
// -> [3,5,7]
s = s[1:4]
// length(3)
fmt.Println(len(s))
// capacity(6)
fmt.Println(cap(s))
// -> [7]
s = s[2:]
// length(1)
fmt.Println(len(s))
// capacity(4)
fmt.Println(cap(s))
Sliceはmake関数で作成できる 配列を割り当て、そのSliceを返す
// len: 5
a := make([]int, 5)
// 第3引数はcap
b := make([]int, 0, 5)
要素の追加はappendで行う サイズの割り当て直しもやってくれる
s := []int{3,5,2}
s = append(s, 4, 4, 2)
// s: [3, 5, 2, 4, 4, 2]
SliceやMapの反復処理
s := []string{"hoge", "fuga", "piyo"}
for index, item := range s {
fmt.Printf("index: %d, item: %s\n", index, item)
}
valueは省略可
s := []string{"hoge", "fuga", "piyo"}
for index := range s {
fmt.Printf("index: %d\n", index)
}
indexを捨てる場合はアンダーバーを使う
s := []string{"hoge", "fuga", "piyo"}
for _, item := range s {
fmt.Printf("item: %s\n", item)
}
var hoge map[string]int
hoge = make(map[string]int)
hoge["test"] = 13
fmt.Println(hoge["test"])
こんな風にも書ける
var fuga = map[int]string{
100: "high",
50: "middle",
10: "low",
}
構造体の場合型名を略せる
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
要素の削除
// delete(map, key)
delete(hoge, "test")
要素の存在チェック
// 二つ目の値にtrue/falseが格納される
elem, ok := m[key]
package main
import (
"golang.org/x/tour/wc"
"fmt"
"strings"
)
func WordCount(s string) map[string]int {
fields := strings.Fields(s)
fmt.Println("Fields are: %q", fields)
var wordCounts map[string]int
wordCounts = make(map[string]int)
for i := 0; i < len(fields); i++ {
word := fields[i]
count, exists := wordCounts[word]
if exists {
wordCounts[word] = count + 1
} else {
wordCounts[word] = 1
}
}
return wordCounts
}
関数は変数、引数、戻り値にできる
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
sum := func(x, y float64) float64 {
return x + y
}
fmt.Println(sum(5, 12)) // 17
fmt.Println(compute(sum)) // 7
}
- 関数オブジェクト
- 変数を関数スコープで解決する
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
prev := 0
current := 0
next := 0
return func() int {
if (prev == 0 && current == 0) {
prev = 1
return 0
}
next = prev + current
prev = current
current = next
return next
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
型にメソッドを追加 レシーバを伴うメソッドの宣言は、レシーバ型が同じパッケージにある必要がある
type Vertex struct {
X, Y float64
}
// レシーバにメソッドを追加したい型を定義
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
任意の型にもメソッドを宣言できる
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
レシーバ自身の値を操作するようなメソッドの場合は、ポインタレシーバを使用する
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// Vertex自身の値を書き換えるので、ポインタレシーバを使う
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(10)
fmt.Println(v.Abs())
}
Interfaceは暗黙的に実装されるため、明示的に実装を宣言する必要はない。
// 宣言
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
// 実装: 変数レシーバである必要がある
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
インターフェース自体の中にある具体的な値が nil の場合、メソッドは nil をレシーバーとして呼び出す。
Go では nil をレシーバーとして呼び出されても適切に処理するメソッドを記述するのが一般的らしい。
type I interface {
M()
}
type T struct {
S string
}
// nilの場合文字列を出力する
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
空のインターフェースは任意の型として利用できる
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
インターフェースの型を調べるにはType assertionsを使う。
func main() {
var i interface{} = "hello"
// okに型チェック結果が格納される
s, ok := i.(string)
// 型チェックがfalseの場合、fはゼロ値になる
f, ok := i.(float64)
}
Type switchesを使うと、複数の型チェックをまとめてできる。
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
文字列を fmt パッケージ に定義されている Stringer インターフェースはstringとして表現することができる型である。
type Stringer interface {
String() string
}
JavaのtoString的扱いに使える?
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
package main
import (
"fmt"
"strings"
)
type IPAddr [4]byte
func (addr IPAddr) String() string{
var sum []string
for i := 0; i < len(addr); i++ {
//sum += fmt.Sprint(addr[i])
sum = append(sum, fmt.Sprint(addr[i]))
}
return strings.Join(sum, ".")
}
func main() {
hosts := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for name, ip := range hosts {
fmt.Printf("%v: %v\n", name, ip)
}
}
Error型はfmt.Stringer に似た組み込みのインタフェース。
type error interface {
Error() string
}
関数にエラーを返させ、呼び出し元でハンドリングするのがお作法?
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
fmt.Println("Converted integer:", i)
データを与えられたバイトスライスへ入れ、入れたバイトのサイズとエラーの値を返すインターフェース。
ストリームの終端は、 io.EOF のエラーで返す。
func (T) Read(b []byte) (n int, err error)
strings.NewReaderを使って文字列を8バイト毎に読み出す。
func main() {
r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
fmt.Printf("b[:n] = %q\n", b[:n])
if err == io.EOF {
break
}
}
}
軽量なスレッド
go f(x, y, z)
で記述する。
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
// 別スレッドで実行される
go say("world")
say("hello")
}
チャネル( Channel )型は、チャネルオペレータの <- を用いて値の送受信をする。
ch <- v
: v をチャネル ch へ送信するv := <-ch
: ch から受信した変数を v へ割り当てるch := make(chan int)
: チャネルを生成する
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y) // -5 17 12
}
チャネルはバッファを持たせられる。
- バッファが詰まった時は、チャネルへの送信をブロックする
- バッファが空の時には、チャネルの受信をブロックする
- いずれも
fatal error: all goroutines are asleep - deadlock!
になる
ch := make(chan int, 100)
送り手はチャネルをクローズできる
- 受け手は二つ目の戻り値でクローズしているか判断できる
- 送り手のチャネルだけをcloseする(受け手はcloseしない)
- closeしたチャネルへ送信すると、パニック( panic )になる
// 受信する値がない、かつ、チャネルが閉じているなら、 ok は false
v, ok := <-ch
- Rangeを使うとチャネルが閉じられるまで、チャネルから値を繰り返し受信し続けられる
for i := range c
- チャネルは、通常closeする必要はない
- closeするのは、これ以上値が来ないことを受け手が知る必要があるときだけ
- 例えば、 range ループを終了する場合
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
select ステートメントは、goroutineを複数の通信操作で待つ
- 複数ある case のいずれかが準備できるようになるまでブロック
- 準備ができた case を実行
- 複数の case の準備ができている場合、 case はランダムに選択される
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
どの case も準備ができていないのであれば、 select の中の default が実行される。
select {
case i := <-c:
// use i
default:
// receiving from c would block
}
MutexのLockとUnlockを使うと排他制御が行える。
// SafeCounter is safe to use concurrently.
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key]++
c.mux.Unlock()
}
// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}