Open23

Tour of Go

koizumi7010koizumi7010

naked returnといって、返り値に名前をつけることができ、変数名として扱うことができる。
returnステートメントで何も書かずに書くことができるが、長い関数内で使うとreadabilityが下がるので短いコード内でのみ使うようにする

hoge.go
func split(sum int) (hoge, fuga int) {
	hoge = sum * 4 / 9
	fuga = sum - hoge
	return
}
koizumi7010koizumi7010

定数( const )は以下のように、:= を使って省略して書くことはできない

sample.go
const Pi = 3.14

func main() {
	const World = "世界"
	fmt.Println("Hello", World)
	fmt.Println("Happy", Pi, "Day")

	const Truth = true
	fmt.Println("Go rules?", Truth)
}
koizumi7010koizumi7010

deferへ渡した関数の実行(ここではfmt.Println)を、呼び出し元の関数(ここではmain())の終わりまで遅延させることができる

defer.go
func main() {
	defer fmt.Println("world")
	fmt.Println("hello")
}
koizumi7010koizumi7010

スライスを作成するのはビルトインの make 関数で可能

sample.go
func main() {
	a := make([]int, 5)
	printSlice("a", a)
}
koizumi7010koizumi7010

スライスやmapを一つずつ反復処理したいときに、for文にrangeを使う
以下のスライスをrangeで繰り返す場合は、2つの変数を返す。
1つ目はそのスライスのindex番号を、2つ目はそのindexに対応する要素を返す。

sample.go
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}
koizumi7010koizumi7010

indexだけ欲しい場合、valueだけ欲しい場合は以下のように省略して記述できる

sample.go
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
         // indexだけ必要な場合
	for index := range pow {
		fmt.Printf("%d\n", i)
         }
         // valueだけ必要な場合
        for _, value := range pow {
                fmt.Printf("%d\n", value)
	}
}
koizumi7010koizumi7010

例えば、"I am learning Go!"というinに対応するwantmap[string]int{"I": 1, "am": 1, "learning": 1, "Go!": 1,}

koizumi7010koizumi7010

testCases (Type : map) のinフィールドをそれぞれWordCount関数の引数に渡して、c.wantのlengthとWordCount(c.in)の返り値のlengthが一緒で、c.wantのインデックスkの値とWordCount(c.in)の返り値のインデックスkが一緒の場合、テストがパスされるようになっている

koizumi7010koizumi7010

関数内で定義された関数(例えば、関数A内で定義された関数B)のことをクロージャー(closure)という
以下の例では、adder()関数はクロージャーを返している

sample.go
func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

この場合は、以下のようにpos, negという変数に返り値であるクロージャーを代入することで、pos(1)やpos(2)のように関数として扱うことができる

sample.go
func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}
koizumi7010koizumi7010

以下2つの代入方法は異なる
1つ目はf0, f1が同時に更新される

sample1.go
f0, f1 = f1, f0 + f1

2つ目のケースは、f0の値がf1に更新された後、f1の値が計算される

sample1.go
f0 = f1
f1 = f0 + f1
koizumi7010koizumi7010

ポインタレシーバ

sample.go
package main

import (
	"fmt"
	"math"
)

type XandY struct {
	X, Y float64
}

func (v XandY) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

// ポインタレシーバ(*)がある場合、ポインタが指す変数を変更することができる
// ポインタが無い場合は、変数を変更することができない
// XandYの値を変更することはできないため、後続の処理に更新された値が反映されない
func (v *XandY) Scale(f float64) float64 {
	v.X = v.X * f
	v.Y = v.Y * f
	return v.X
}

func main() {
	v := XandY{X:3, Y:4}
	fmt.Println(v.Scale(10))
	fmt.Println(v.Abs())
}
koizumi7010koizumi7010

Exercise: Stringers

解答例

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
// IPAddr型にString()メソッドを追加する
func (i IPAddr) String() string {
	return fmt.Sprintf("%d.%d.%d.%d", i[0], i[1], i[2], i[3])
}

func main() {
         // string型をキーに、IPAddr型を値に持つmap型のhostsという変数を宣言
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
         // hostsをfor range文でループ処理させる
         // この時、key , valueの順番にmapの値が代入される(sliceの場合だとindexとvalue)
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip)
	}
}