Go言語の多重エラー処理(複数エラー)のパターン集!初心者でもわかる安全なエラーハンドリング
生徒
「先生、Go言語で複数のエラーが同時に起きたときって、どうやって処理したらいいんですか?」
先生
「いい質問ですね。Go言語では、ひとつの処理で複数のエラーが起きることもあります。そんな時は『多重エラー処理』を使って、全てのエラー情報をまとめて扱う方法があります。」
生徒
「どうやって複数のエラーをまとめるんですか?初心者でもわかるように教えてください!」
先生
「はい、これから基本的なやり方やコード例を使って丁寧に説明しますね!」
1. 多重エラー処理とは?
プログラムではエラーが発生すると、その原因を特定して適切に対処する必要があります。多重エラー処理とは、一つの関数や処理の中で起きた複数のエラーを「まとめて一括で扱う」ための考え方・テクニックのことです。Go言語のエラーハンドリングでは、この複数エラーをどう整理するかがとても大事になります。
たとえば、会員登録フォームを考えてみましょう。ユーザー名・メールアドレス・パスワードを一度に入力してもらうとき、それぞれに「未入力」「形式が間違っている」といったエラーが同時に起きる可能性があります。このとき、最初に見つかったエラーだけを返してしまうと、ユーザーは何度も入力し直さなければならず、あとから他のエラーに気づくことになります。
そこで、Go言語の多重エラー処理では「見つかったエラーをひとまず全部集めておき、まとめて返す」という考え方をします。こうすると、ユーザーには「名前が未入力」「メールアドレスが空」「パスワードが短い」といった複数のエラーを一度に伝えられ、開発者にとっても原因をまとめて確認しやすくなります。
package main
import (
"errors"
"fmt"
)
// 簡単な例:入力チェックで複数エラーを集める
func validateUser(name, email string) []error {
var errs []error
if name == "" {
errs = append(errs, errors.New("名前が未入力です"))
}
if email == "" {
errs = append(errs, errors.New("メールアドレスが未入力です"))
}
return errs
}
func main() {
// わざと空の値を渡してエラーを発生させる
errs := validateUser("", "")
if len(errs) > 0 {
fmt.Println("入力内容に問題があります:")
for _, err := range errs {
fmt.Println("-", err)
}
} else {
fmt.Println("入力に問題はありません")
}
}
このサンプルでは、名前とメールアドレスに対してそれぞれチェックを行い、問題があればerrsという変数にエラーをどんどん追加しています。最後に、エラーが一つでもあれば、まとめて画面に表示しています。ポイントは「どこかでエラーが出たらすぐに処理を中断する」のではなく、「最後までチェックして、見つかったエラーを全部集めてから報告する」という流れにしていることです。
このように、Go言語で複数エラーを扱う多重エラー処理を意識しておくと、ユーザーにとっても開発者にとってもわかりやすいエラーメッセージ設計ができるようになります。次の章からは、この考え方を実現する具体的な書き方やパターンを、実際のGoコードを使いながら詳しく見ていきます。
2. エラーとは?初心者にわかりやすく説明
ここでいったん立ち止まって、そもそもエラーとは何なのかを整理しておきましょう。エラーとは、プログラムの実行中に「想定していない問題が発生した」ということを知らせるための情報です。たとえば「ファイルが見つからない」「ネットワークに接続できない」「入力された値が不正」など、現実のトラブルをプログラムの中で表現したものがエラーです。
Go言語のエラー処理では、特別な文法というよりも、関数の戻り値としてエラー情報(error型)を返すのが基本のスタイルです。つまり、処理の結果の値とエラーが起きたかどうかをセットで返すイメージです。エラーがないときはnil(何も入っていないことを表す値)を返し、問題が起きたときだけerror型の値を返します。
package main
import (
"errors"
"fmt"
)
// 年齢をチェックして、問題があれば error を返す
func checkAge(age int) error {
if age < 0 {
return errors.New("年齢がマイナスです")
}
if age < 18 {
return errors.New("18歳未満です")
}
// 問題がなければ nil(エラーなし)を返す
return nil
}
func main() {
err := checkAge(15)
if err != nil {
// エラーが入っている場合
fmt.Println("エラーが発生しました:", err)
} else {
// エラーがない場合
fmt.Println("年齢チェックに問題はありません")
}
}
このサンプルでは、checkAgeという関数が年齢をチェックし、条件に合わなければerror型の値を返します。main関数側では、戻ってきたerrがnilかどうかを確認し、nilでなければ「エラーが発生した」と判断してメッセージを表示します。Go言語ではこのように、if err != nil { ... }というパターンでエラーハンドリングを行うのが定番です。
まずは「エラーはただの値」「nilならエラーなし、nilでなければ何か問題が起きている」という感覚をつかんでおくと、次の章で出てくる複数エラー処理(多重エラー処理)も理解しやすくなります。1つのerrorを扱う流れがイメージできれば、これを複数集めて扱う方法も自然と見えてきます。
3. 複数のエラーをまとめる方法1:エラーのスライスを使う
まず最初に試しやすいのが、エラーをそのまま配列のように並べて持つ方法です。Go言語では、同じ型の値をまとめて扱うためにスライスという仕組みがあります。これを使って、見つかったエラーをひとつずつスライスに追加していけば、「どの処理で、どんなエラーが起きたのか」を後からまとめて確認できるようになります。
イメージとしては、「やることリスト」に問題点を書き足していく感覚に近いです。チェックのたびに「ここがダメだった」というメモ(error)を1行ずつ足していき、最後に「今日の問題点リスト」としてまとめて見る、という形です。
package main
import (
"errors"
"fmt"
)
// 複数の処理をしてエラーをスライスで返す例
func processAll() []error {
var errs []error
// 処理1でエラー発生
errs = append(errs, errors.New("処理1でエラー:ファイルが見つかりません"))
// 処理2は問題なし(何も追加しない)
// 処理3でエラー発生
errs = append(errs, errors.New("処理3でエラー:書き込みに失敗しました"))
return errs
}
func main() {
errors := processAll()
if len(errors) > 0 {
fmt.Println("複数のエラーが発生しました:")
for _, err := range errors {
fmt.Println("-", err)
}
} else {
fmt.Println("エラーはありませんでした")
}
}
このサンプルでは、processAllという関数の中で3つの処理を行い、「エラーが起きたものだけ」をerrsスライスにappendで追加しています。最後にerrsをそのまま戻り値として返し、main関数側ではlen(errors)で「エラーがいくつあったか」を確認しながら、中身を1件ずつ表示しています。
ポイントは、エラーが起きた瞬間に処理を中断してしまうのではなく、「いったん全部の処理を試してみて、その結果としてエラーの一覧を返す」という流れにしているところです。これによって、「1つ直したらまた別のエラーが出てきた」という状況を減らしやすくなり、複数のエラーをまとめて修正しやすくなります。まずはこのように[]error型のスライスを使って、複数エラーを素直に集めるパターンに慣れておくと、次に紹介する応用的な方法も理解しやすくなります。
4. 複数のエラーをまとめる方法2:カスタムエラー型を作る
もう少し便利に使いたい場合は、複数のエラーをまとめるための独自のエラー型(カスタムエラー型)を作る方法があります。これにより、エラーを一つの値として返しつつ、内部に複数のエラーを持たせられます。
package main
import (
"fmt"
"strings"
)
// 複数エラーをまとめるカスタムエラー型
type MultiError struct {
Errors []error
}
// errorインターフェースを満たすためのError()メソッド
func (m *MultiError) Error() string {
var messages []string
for _, err := range m.Errors {
messages = append(messages, err.Error())
}
return "複数エラー: " + strings.Join(messages, "; ")
}
func main() {
errs := &MultiError{}
errs.Errors = append(errs.Errors, fmt.Errorf("ファイルが見つかりません"))
errs.Errors = append(errs.Errors, fmt.Errorf("接続タイムアウト"))
if len(errs.Errors) > 0 {
fmt.Println(errs.Error())
}
}
この方法なら、MultiErrorを一つのエラーとして扱えますし、詳細なエラーも簡単に確認できます。
5. 複数エラー処理の便利なライブラリ
実務では、多重エラー処理をもっと簡単にするために、Goのコミュニティが作ったライブラリを使うことも多いです。
例えば、hashicorp/go-multierrorというライブラリは、複数のエラーを簡単にまとめて扱えます。
import (
"fmt"
"github.com/hashicorp/go-multierror"
)
func main() {
var result error
// 複数のエラーを追加
result = multierror.Append(result, fmt.Errorf("エラー1"))
result = multierror.Append(result, fmt.Errorf("エラー2"))
if result != nil {
fmt.Println(result)
}
}
このように、ライブラリを使うと複数エラーの扱いが楽になります。
6. 複数エラー処理で気をつけるポイント
- 複数のエラーが起きる場面を想定して、適切に情報をまとめることが大切です。
- エラーを無視せず、必ずログやユーザー通知などに活用しましょう。
- 単純に最初のエラーだけを返すのではなく、多重エラーとして扱うことで問題発見がしやすくなります。
- エラーをまとめるときは可読性を保つために、メッセージの区切り方や形式を工夫しましょう。
まとめ
Go言語における多重エラー処理(複数エラーのまとめ方)は、実践的な開発では非常に重要な考え方です。特に、ファイル処理・ネットワーク通信・複数の検証処理が重なるようなプログラムでは、一つの処理の中で複数のエラーが同時に発生することも珍しくありません。そのため、すべてのエラーを正確に把握しておくことは、後から問題の原因を追跡したり、ログに残したり、ユーザーに適切なメッセージを提示するうえで欠かせない作業になります。今回の記事で学んだように、複数エラーを扱うための方法はいくつかあり、スライスでまとめる基本的なやり方から、カスタムエラー型を定義して読みやすく整理された形式にする方法、そしてコミュニティが提供する便利なライブラリを用いる手法まで、段階的にレベルアップできる構成になっています。 特に、Go言語の特徴として「エラーを戻り値として返す」文化があり、例外処理が存在しない分、エラーの扱いについて細かい部分まで自分で制御する必要があります。そのため、多重エラー処理に慣れることで、日常的な開発の中でより安全で信頼できるコードを書くための基礎となります。また、複数のエラーが発生する可能性がある場面では、最初のエラーだけでなく、すべてを検出して返せるような仕組みを作ることで、より正確で丁寧なプログラム設計が可能になります。 さらに、スライスにエラーをまとめて返す方法は構造がシンプルであり、初心者でも取り入れやすい点が大きな魅力です。一方、カスタムエラー型を用いる方法は、複数のエラーを1つのエラーとして扱えるため、呼び出し側でのコードがすっきりし、エラー全体の読みやすさが格段に向上します。そして、go-multierrorのようなライブラリは、既に整備された仕組みを使えるため、実装の手間を減らしつつ堅牢な多重エラー処理を取り入れることができます。 こうした多重エラー処理の基礎を身につけておけば、API開発、ファイル操作、データ検証など、幅広い場面で応用でき、初心者から中級者へステップアップする大きなきっかけとなります。
サンプルプログラムで学びを深めよう
以下は、スライス・カスタム型・複数パターンを組み合わせた応用的な多重エラー処理の例です。この記事全体で解説してきた内容をまとめながら、複数エラーを扱う流れを復習できる構成になっています。
package main
import (
"errors"
"fmt"
"strings"
)
// カスタムの複数エラー型
type MultiError struct {
Errors []error
}
func (m *MultiError) Error() string {
var list []string
for _, err := range m.Errors {
list = append(list, err.Error())
}
return "複数の問題: " + strings.Join(list, " / ")
}
// いくつかのチェック処理を行う例
func validateData(name string, age int) error {
var multi MultiError
if name == "" {
multi.Errors = append(multi.Errors, errors.New("名前が入力されていません"))
}
if age < 0 {
multi.Errors = append(multi.Errors, errors.New("年齢がマイナスです"))
}
if age > 120 {
multi.Errors = append(multi.Errors, errors.New("年齢の値が不正です"))
}
if len(multi.Errors) > 0 {
return &multi
}
return nil
}
func main() {
err := validateData("", -5)
if err != nil {
fmt.Println("エラー一覧:", err)
} else {
fmt.Println("すべてのチェックに成功しました")
}
}
このサンプルでは複数の条件に応じてエラーが追加され、最後に一つのエラーとして返される仕組みになっています。実際の開発でも、複数項目を同時にチェックする場面は多く、この書き方は非常に役立ちます。特にフォーム入力や設定ファイルの検証では、ユーザーが修正すべき部分を明確に提示できるため、とても親切なエラーメッセージ設計になります。
生徒
「先生、今回の多重エラー処理は本当に勉強になりました!複数のエラーをまとめるって想像したより便利なんですね。」
先生
「その通りです。特にGo言語では、エラー処理を丁寧に書くことがプログラムの品質に直結します。まとめて扱えると、とても見通しがよくなりますよ。」
生徒
「スライスでまとめる方法と、カスタム型でまとめる方法では何が違うんですか?」
先生
「スライスはシンプルで扱いやすいですが、呼び出し側ではエラーの扱いが少し複雑になります。その点、カスタム型を使えばひとつのエラーとして扱えるので、コードがより読みやすくなりますね。」
生徒
「なるほど!ライブラリを使う方法もあるって知れて勉強になりました。実務ではそういう便利ツールも使っていくんですね。」
先生
「その通り。基本がわかっていれば、どの方法も適材適所で使い分けられます。今回覚えた内容は、実際の開発でもきっと役に立ちますよ。」
この記事を読んだ人からの質問
プログラミング初心者からのよくある疑問/質問を解決します
Go言語におけるエラーとは何ですか?
Go言語におけるエラーとは、ファイルが見つからない・ネットワークに接続できないなど、プログラム実行中に問題が起きたことを示す情報で、通常はerror型で返されます。
Go言語で多重エラー処理とはどういう意味ですか?
Go言語の多重エラー処理とは、一つの処理の中で複数のエラーが同時に発生した場合に、それらをまとめて扱う手法のことを指します。
【超入門】ゼロから始めるGo言語プログラミング:最速で「動くアプリ」を作るマンツーマン指導
「プログラミングの仕組み」が根本からわかる。Go言語でバックエンド開発の第一歩を。
本講座を受講することで、単なる文法の暗記ではなく、「プログラムがコンピュータの中でどう動いているか」という本質的な理解につながります。シンプルながら強力なGo言語(Golang)を通じて、現代のバックエンドエンジニアに求められる基礎体力を最短距離で身につけます。
具体的な開発内容と環境
【つくるもの】
ターミナル(黒い画面)上で動作する「対話型計算プログラム」や、データを整理して表示する「ミニ・ツール」をゼロから作成します。自分の書いたコードが形になる感動を体験してください。
【開発環境】
プロの現場でシェアNo.1のVisual Studio Code (VS Code)を使用します。インストールから日本語化、Go言語用の拡張機能設定まで、現場基準の環境を一緒に構築します。
この60分で得られる3つの理解
「なぜ動くのか」という設定の仕組みを理解し、今後の独学で詰まらない土台を作ります。
データの種類やメモリの概念など、他言語にも通じるプログラミングの本質を学びます。
ただ動くだけでなく、誰が見ても分かりやすい「綺麗なコード」を書くための考え方を伝授します。
※本講座は、将来的にバックエンドエンジニアやクラウドインフラに興味がある未経験者のためのエントリー講座です。マンツーマン形式により、あなたの理解度に合わせて進行します。
初めてのGo言語を一緒に学びましょう!