前回のブログ記事で、制御構文(if、for、switch)を学んだあなたに向けて、今回は関数についてご紹介しよう。
関数を理解することで、コードを整理し、再利用可能な部品として扱えるようになる。
これにより、保守性の高いプログラムを作成できる。
1. 関数の基本「コードを再利用する」
関数は、特定の処理をまとめて名前をつけたものである。一度定義すれば、何度でも呼び出すことができる。
基本的な関数の定義
package main
import "fmt"
// 引数なし、戻り値なし
func sayHello() {
fmt.Println("こんにちは!")
}
func main() {
sayHello() // 関数の呼び出し
}
// 出力: こんにちは!関数定義の構造:
func: 関数を定義するキーワードsayHello: 関数名(): 引数のリスト(今回は空){}: 関数の本体
引数を受け取る関数
// 引数あり、戻り値なし
func greet(name string) {
fmt.Println("こんにちは、", name, "さん!")
}
func main() {
greet("太郎") // 出力: こんにちは、 太郎 さん!
greet("花子") // 出力: こんにちは、 花子 さん!
}戻り値を返す関数
// 引数あり、戻り値あり
func add(a int, b int) int {
return a + b
}
func main() {
result := add(10, 20)
fmt.Println("10 + 20 =", result)
// 出力: 10 + 20 = 30
}戻り値の型:
- 関数名と引数の後に
intと書くことで、戻り値の型を指定する return文で値を返す
同じ型の引数は省略できる
// a, b が両方 int なので省略可能
func multiply(a, b int) int {
return a * b
}
func main() {
product := multiply(5, 6)
fmt.Println("5 × 6 =", product)
// 出力: 5 × 6 = 30
}2. 複数の戻り値(Goの特徴的な機能)
Goでは、関数から複数の値を返すことができる。これはエラーハンドリングで非常に重要な機能である。
2つの値を返す関数
// 割り算の商と余りを同時に返す
func divmod(a, b int) (int, int) {
quotient := a / b // 商
remainder := a % b // 余り
return quotient, remainder
}
func main() {
q, r := divmod(17, 5)
fmt.Printf("17 ÷ 5 = %d 余り %d\n", q, r)
// 出力: 17 ÷ 5 = 3 余り 2
}戻り値の一部を無視する
戻り値の一部が不要な場合、_(アンダースコア)で無視できる。
func main() {
_, remainder := divmod(20, 3)
fmt.Println("余りのみ:", remainder)
// 出力: 余りのみ: 2
}3. エラーハンドリングの基本
Goでは、エラーを戻り値として返すのが一般的である。
error型を返す関数
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("0で割ることはできません")
}
return a / b, nil // エラーがない場合はnilを返す
}
func main() {
// 正常なケース
result, err := divide(10, 2)
if err != nil {
fmt.Println("エラー:", err)
} else {
fmt.Println("結果:", result)
}
// 出力: 結果: 5
// エラーケース
result, err = divide(10, 0)
if err != nil {
fmt.Println("エラー:", err)
} else {
fmt.Println("結果:", result)
}
// 出力: エラー: 0で割ることはできません
}Goのエラーハンドリングのパターン:
- 関数は
(結果, error)の形で値を返す - 呼び出し側で
if err != nilでエラーをチェック - エラーがなければ
nilを返す
これはGoの重要な慣習である。
4. 可変長引数「任意の数の引数を受け取る」
...を使うと、任意の数の引数を受け取ることができる。
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
fmt.Println("合計:", sum(1, 2, 3)) // 出力: 合計: 6
fmt.Println("合計:", sum(1, 2, 3, 4, 5)) // 出力: 合計: 15
fmt.Println("合計:", sum(10, 20)) // 出力: 合計: 30
}可変長引数の特徴:
numbers ...intは、intのスライスとして扱われる- 引数の数は任意(0個でもOK)
rangeで各要素にアクセスできる
5. 名前付き戻り値「戻り値に名前をつける」
Goでは、戻り値に名前をつけることができる。
func rectangle(width, height int) (area int, perimeter int) {
area = width * height
perimeter = 2 * (width + height)
return // 名前付き戻り値は return だけでOK
}
func main() {
area, perimeter := rectangle(5, 10)
fmt.Printf("面積: %d, 周囲: %d\n", area, perimeter)
// 出力: 面積: 50, 周囲: 30
}名前付き戻り値の利点:
- ドキュメントとして機能する
- 裸の
return(値を書かない)が使える - 関数の途中で値を設定できる
注意点:
- 短い関数では逆に読みにくくなることもある
- 使いすぎないように注意
6. 実践:すべてを組み合わせた例
学んだ内容を使って、簡単な計算機プログラムを作ってみよう。
package main
import (
"errors"
"fmt"
)
// 四則演算を行う関数(エラーハンドリング付き)
func calculate(a, b float64, operator string) (float64, error) {
switch operator {
case "+":
return a + b, nil
case "-":
return a - b, nil
case "*":
return a * b, nil
case "/":
if b == 0 {
return 0, errors.New("0で割ることはできません")
}
return a / b, nil
default:
return 0, errors.New("未対応の演算子です: " + operator)
}
}
func main() {
fmt.Println("=== 簡易計算機 ===")
// テストケース
testCases := []struct {
a, b float64
operator string
}{
{10, 5, "+"},
{10, 5, "-"},
{10, 5, "*"},
{10, 5, "/"},
{10, 0, "/"}, // エラーケース
{10, 5, "%"}, // エラーケース
}
for _, tc := range testCases {
result, err := calculate(tc.a, tc.b, tc.operator)
if err != nil {
fmt.Printf("%.1f %s %.1f = エラー: %v\n",
tc.a, tc.operator, tc.b, err)
} else {
fmt.Printf("%.1f %s %.1f = %.1f\n",
tc.a, tc.operator, tc.b, result)
}
}
}実行結果:
=== 簡易計算機 ===
10.0 + 5.0 = 15.0
10.0 - 5.0 = 5.0
10.0 * 5.0 = 50.0
10.0 / 5.0 = 2.0
10.0 / 0.0 = エラー: 0で割ることはできません
10.0 % 5.0 = エラー: 未対応の演算子です: %プログラムのポイント
- 関数
calculate:- 2つの数値と演算子を受け取る
(結果, error)の形で戻り値を返す- switch文で演算子ごとに処理を分岐
- エラーケースを適切に処理
- main関数:
- テストケースを用意して一括テスト
- エラーハンドリングを実践
- 結果を見やすく表示
関数を適切に使うことで、コードの再利用性と保守性が大幅に向上する。
次のステップとしては、スライスとマップについて学んでいくとよいだろう。
この記事のサンプルコードは、私のGitHubリポジトリで公開している: go-learning/basics/04-functions
GitHub Codespacesを使えば、ブラウザ上ですぐに実行できる!



コメント