チュートリアル

Go基礎:関数と構造体

Go入門関数構造体
広告エリア

関数

基本的な関数

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

まとめ

  • 関数は複数の戻り値を返せる
  • エラーは戻り値として返す(例外なし)
  • 構造体でデータをまとめる
  • メソッドは構造体に紐づく関数
  • インターフェースでポリモーフィズム
  • ポインタで値を直接変更

次回は並行処理について学びます。

広告エリア