updated on 2020-10-31
一連の処理をまとめたもの
関数の種類
引数を指定して呼び出す
サンプルコード
package main import "fmt" func main() { sum := repeat("Test!", 2+1)
fmt.Print(sum)
//
} func repeat(word string, reps int) string { var concat string for i := 0; i < reps; i++ { concat += word } return concat }Test!Test!Test!
print/println | 表示を行う |
make | コンポジット型の初期化 |
new | 指定した型のメモリの確保 |
len/cap | スライスなどの長さ/容量を返す |
copy | スライスのコピーを行う |
delete | マップから指定したキーのエントリを削除 |
complex | 複素数型を作成 |
imag/real | 複素数の虚部/実数部を取得 |
panic/revocer | パニックを起こす/回復する |
func 関数名 (引数 型) { // do something }
サンプルコード
package main import "fmt" func add(x, y int) int { return x + y } func swap(x, y int) (int, int) { return y, x } func main() { fmt.Println(add(10, 20)) fmt.Println(swap(10, 20)) }
(コンソール出力)
30
20 10
カンマで区切って値を受け取る
x, y := swap(10, 20)
省略したい場合はブランク変数(_)を用いる
x, _ := swap(10, 20)
_, y := swap(10, 20)
ちなみに、勉強のためにswap関数を使っているが、以下のようにカンマくぐりを使えば、値の入れ替えは、一時変数や関数を使わずにできる
x, y := y, x
名前付き戻り値
以下の例では、x2, y2が名前付き戻り値
サンプルコード
package main func swap(x, y int) (x2, y2 int) { y2, x2 = x, y // return x2, y2 return // 明示しない場合は戻り値用の変数の値が返される } func main() { x, y := swap(10, 20) println(x, y) }
(コンソール出力)
20 10
名前のない関数で、別名クロージャと呼ばれる
以下の形式で使われることが多い
func (引数 型) {
// do something
}(値)
サンプルコード
package main import "fmt" func main() { msg := "Hello, 世界" // 無名関数 引数なし func() { fmt.Println(msg) }() // 無名関数 引数あり func(word string) { fmt.Println(word) }("テスト") // 無名関数 代入 f := func(src string) string { return "Hello, " + src } fmt.Println(f("テスト")) }
(コンソール出力)
Hello, 世界
テスト
Hello, テスト
定義と実行のタイミングを気をつける
関数外の変数(自由変数)を参照している場合
実行のタイミングでは値が変わっている可能性がある
package main import "fmt" func main() { fs := make([]func(), 4) for i := range fs { fs[i] = func() { fmt.Println(i) } fs[i]() } for _, f := range fs { f() } }
(コンソール出力)
0
1
2
3
3
3
3
3
関数はファーストクラスオブジェクト
変数への代入
引数に渡す
戻り値で返す
package main import "fmt" func main() { fs := make([]func() string, 2) fs[0] = func() string { return "hoge" } fs[1] = func() string { return "fuga" } for _, f := range fs { fmt.Println(f()) fmt.Printf("型 -> %T\n", f) } }
(コンソール出力)
hoge
型 -> func() string
fuga
型 -> func() string
Goには値の型として、値型と参照型が存在する。
値型
参照型
値型
値型 | |
---|---|
1 | 数値 |
2 | 構造体 |
3 | 配列 |
参照型
参照型 | |
---|---|
1 | インターフェース |
2 | チャンネル |
3 | マップ |
4 | スライス |
サンプル
package main import "fmt" const alternative = -999 type Strct struct { a, b int } func changeInt(aryNumber int) { aryNumber = alternative } func changeArray(aryVar [3]int) { aryVar[0] = alternative } func changeSlice(sliceVar []int) { sliceVar[0] = alternative } func changeMap(mapVar map[string]int) { mapVar["a"] = alternative } func changeStruct(strctVar Strct) { strctVar.a = alternative } func main() { fmt.Print("Int:\t値型\t") intVar := 1 fmt.Printf("Before %v => ", intVar) changeInt(intVar) fmt.Printf("After %v\n", intVar) // 値渡しなので元の値は変わらない fmt.Print("Array:\t値型\t") arrayVar := [3]int{0, 1, 2} fmt.Printf("Before %v => ", arrayVar) changeArray(arrayVar) fmt.Printf("After %v\n", arrayVar) // 値渡しなので元の値は変わらない fmt.Print("Struct:\t値型\t") strctVar := Strct{a: 0, b: 1} fmt.Printf("Before %v => ", strctVar) changeStruct(strctVar) fmt.Printf("After %v\n", strctVar) // 値渡しなので元の値は変わらない fmt.Print("Slice:\t参照型\t") sliceVar := []int{0, 1, 2} fmt.Printf("Before %v => ", sliceVar) changeSlice(sliceVar) fmt.Printf("After %v\n", sliceVar) // 参照渡しなので元の値も変わる fmt.Print("Map:\t参照型\t") mapVar := map[string]int{"a": 0, "b": 1, "c": 2} fmt.Printf("Before %v => ", mapVar) changeMap(mapVar) fmt.Printf("After %v\n", mapVar) // 参照渡しなので元の値も変わる }
参照型(内部でポインタが用いられているデータ型)
これらの型は、破壊的な操作になるため、ポインタを用いる必要がないことが多い
func f(xp *int intのポインタ型) {
*xp = 100 *でポインタの指す先に値を入れる
}
func main() {
var x int
f(&x) &でポインタを取得
println(x) // 初期値の0ではなく、100が出力される
}
ポインタを使った偶奇判定
package main import "fmt" func main() { for i := 1; i <= 100; i++ { judge(&i) // iのポインタ(メモリ上の格納場所)を引数に渡す } } func judge(ip *int) { if *ip%2 == 0 { fmt.Printf("%d-偶数\n", *ip) } else { fmt.Printf("%d-奇数\n", *ip) } }
(コンソール出力)
1-奇数
2-偶数
...
100-偶数
ポインタを使った値の入れ替え
package main
func main() {
n, m := 10, 20
swap(&n, &m)
println(n, m) // 20 10
}
func swap(np, mp *int) {
*np, *mp = *mp, *np
}
(コンソール出力)
20 10
package main import "fmt" func main() { a := 0 b := 0 sampleFunc(a, &b) fmt.Printf("a: %d\n", a) // 値渡し fmt.Printf("b: %d\n", b) //参照渡し } func sampleFunc(a int, b *int) { a = a + 1 *b = *b + 1 }
(コンソール出力)
a: 0
b: 1
package main import "strconv" type Profile struct { Name string Age int } func (p Profile) Set(name string, age int) { p.Name = name p.Age = age } func (p *Profile) Pointer_Set(name string, age int) { p.Name = name p.Age = age } func (p Profile) String() string { return "Name: " + p.Name + ", Age: " + strconv.Itoa(p.Age) } func (p Profile) Print() { s := p.String() println(s) } func main() { var p Profile p.Set("Endo", 40) p.Print() // Name: (空文字), Age: 0 p.Pointer_Set("Tanaka", 40) p.Print() // Name: Tanaka, Age: 31 }
(コンソール出力)
Name: , Age: 0
Name: Tanaka, Age: 40