tour of goで学んだことのメモ
Named return values
Goでの戻り値となる変数に名前をつける( named return value )ことができます。戻り値に名前をつけると、関数の最初で定義した変数名として扱われます。
https://go-tour-jp.appspot.com/basics/7
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
// return x yとしなくてもx, yをリターンしてくれる(naked return)
return
}
func main() {
fmt.Println(split(17))
}
if
Goのifは()は不要で{}は必須
if x < 0 {
return sqrt(-x) + "i"
}
If with a short statement
ifの条件部分で宣言された変数はifのスコープ内でのみ有効
Defer
defer ステートメントは、 defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させるものです。
defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。
https://go-tour-jp.appspot.com/flowcontrol/12
Stacking defers
defer へ渡した関数が複数ある場合、その呼び出しはスタック( stack )されます。 呼び出し元の関数がreturnするとき、 defer へ渡した関数は LIFO(last-in-first-out) の順番で実行されます。
https://go-tour-jp.appspot.com/flowcontrol/13
最後から最初って順番で実行される
Pointers
var p *int
初期値はnilになる
i := 42
p := &i
pはiのポインタを定義している
fmt.Println(*p)
ポインタpに存在する値を呼ぶ
Pointers to structs
structのフィールドは、structのポインタを通してアクセスすることもできます。
https://go-tour-jp.appspot.com/moretypes/4
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 300
fmt.Println(v)
}
vの値は{300, 2}になる
Arrays
var a [10]int
10個の数字の配列を宣言している
Slices
配列は固定長です。一方で、スライスは可変長です。より柔軟な配列と見なすこともできます。 実際には、スライスは配列よりもより一般的です。
https://go-tour-jp.appspot.com/moretypes/7
sliceとmapの違いを完全理解した
Slices are like references to arrays
スライスは配列への参照のようなものです。
スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。
https://go-tour-jp.appspot.com/moretypes/8
sliceは参照しているだけなので、sliceの値を変更したら元の配列の値も変わるよって理解
Slice length and capacity
スライスは長さ( length )と容量( capacity )の両方を持っています。
https://go-tour-jp.appspot.com/moretypes/11
長さは含まれる要素の数
容量は元の要素の数
Creating a slice with make
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
Function closures
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
sumの値はpos, negで別れているが、それぞれで参照されている(sumの値は引き継がれる)
Methods
型にメソッド( method )を定義できます。
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Vertexという型にAbsという関数を定義している
Pointer receivers
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
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())
}
func (v *Vertex) Scale(f float64) {
の*
があることでVertext{3, 4}の値を変更することができる
メソッドがポインタレシーバである場合、呼び出し時に、変数、または、ポインタのいずれかのレシーバとして取ることができます:
https://go-tour-jp.appspot.com/methods/6
var v Vertex
v.Scale(5) // OK
p := &v
p.Scale(10) // OK
vはポインタではないがGoのほうでポインタレシーバとして自動的に呼び出されるためコンパイルが通る
Choosing a value or pointer receiver
値レシーバとは?
func (p Person) Greet(msg string) {
fmt.Printf("%s, I'm %s.\n", msg, p.Name)
}
ポインタレシーバとは?
func (pp *Person) Shout(msg string) {
fmt.Printf("%s!!!\n", msg)
}
Interface values
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
describe(i)
でvalueと、型を引数として渡していることが分かる
The empty interface
interface{}
はjsでいうany
に近い
goにおけるinterfaceとstructの違い
struct
構造体
key: valueでなりたっているイメージ
インターフェース
メソッドの組み合わせ