関数
基本的な関数
func add(a int, b int) int {
return a + b
}
// 同じ型の引数は省略可能
func add2(a, b int) int {
return a + b
}
// 戻り値なし
func greet(name string) {
fmt.Println("Hello,", name)
}
複数の戻り値
func divide(a, b int) (int, int) {
return a / b, a % b
}
quotient, remainder := divide(10, 3)
// 一部を無視
q, _ := divide(10, 3)
名前付き戻り値
func divide(a, b int) (quotient, remainder int) {
quotient = a / b
remainder = a % b
return // 名前付き戻り値を返す
}
エラー処理
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(result)
可変長引数
func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
// スライスを展開
nums := []int{1, 2, 3}
fmt.Println(sum(nums...))
関数型と高階関数
// 関数型
type Operation func(int, int) int
// 関数を引数に取る
func apply(a, b int, op Operation) int {
return op(a, b)
}
add := func(a, b int) int { return a + b }
result := apply(3, 5, add) // 8
// 無名関数
result2 := apply(3, 5, func(a, b int) int {
return a * b
})
クロージャ
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3
構造体
構造体の定義
type User struct {
ID int
Name string
Age int
}
// インスタンス作成
user1 := User{ID: 1, Name: "太郎", Age: 25}
user2 := User{1, "太郎", 25} // フィールド順
// ゼロ値
var user3 User // {0, "", 0}
// new
user4 := new(User) // *User型(ポインタ)
// フィールドアクセス
fmt.Println(user1.Name)
user1.Age = 26
メソッド
type Rectangle struct {
Width float64
Height float64
}
// 値レシーバ(コピーを受け取る)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// ポインタレシーバ(元の値を変更可能)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
rect := Rectangle{10, 5}
fmt.Println(rect.Area()) // 50
rect.Scale(2)
fmt.Println(rect.Area()) // 200
埋め込み(継承的な機能)
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "..."
}
type Dog struct {
Animal // 埋め込み
Breed string
}
dog := Dog{
Animal: Animal{Name: "ポチ"},
Breed: "柴犬",
}
fmt.Println(dog.Name) // ポチ(Animalのフィールド)
fmt.Println(dog.Speak()) // ...(Animalのメソッド)
インターフェース
type Speaker interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "ワンワン"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return "ニャー"
}
// インターフェースを使った関数
func MakeSpeak(s Speaker) {
fmt.Println(s.Speak())
}
dog := Dog{Name: "ポチ"}
cat := Cat{Name: "タマ"}
MakeSpeak(dog) // ワンワン
MakeSpeak(cat) // ニャー
空インターフェース
// 任意の型を受け取れる
func printAny(v interface{}) {
fmt.Println(v)
}
// Go 1.18以降は any が使える
func printAny2(v any) {
fmt.Println(v)
}
printAny("hello")
printAny(42)
printAny(true)
// 型アサーション
func describe(v interface{}) {
switch val := v.(type) {
case string:
fmt.Println("文字列:", val)
case int:
fmt.Println("整数:", val)
default:
fmt.Println("その他:", val)
}
}
ポインタ
func main() {
x := 10
p := &x // xのポインタ
fmt.Println(x) // 10
fmt.Println(p) // メモリアドレス
fmt.Println(*p) // 10(デリファレンス)
*p = 20
fmt.Println(x) // 20
}
// ポインタを使って値を変更
func increment(n *int) {
*n++
}
x := 10
increment(&x)
fmt.Println(x) // 11
まとめ
- 関数は複数の戻り値を返せる
- エラーは戻り値として返す(例外なし)
- 構造体でデータをまとめる
- メソッドは構造体に紐づく関数
- インターフェースでポリモーフィズム
- ポインタで値を直接変更
次回は並行処理について学びます。