Go(Golang)を学び始めたばかりの人にとって、「if文」は最初の関門の一つです。
他の言語と似ているようで微妙に違うGoのif文は、書き方にクセがあり、知らずにエラーを出してしまうこともあります。
特に、C言語やJavaから来た人は「なぜカッコがエラーになるの?」「なぜelseが改行できないの?」と戸惑うことが多いです。
この記事では、Go言語におけるif
文の基本から、初学者がつまずきやすいポイント、実用的な書き方のコツまで、わかりやすくまとめました。
「ifの中で変数定義できるの?」「else ifは使える?」「スコープって何?」といった疑問にも、具体例つきでお答えします!
Go言語におけるif文の基本構文
基本形(最もシンプルな例)
if 条件式 {
// 条件がtrueのときの処理
}
Goの特徴:
- 条件式のカッコ
()
は不要(エラーになる) - 波カッコ
{}
は必須(省略不可)
具体例で理解しよう
package main
import "fmt"
func main() {
x := 10
if x > 5 {
fmt.Println("xは5より大きい")
}
// 出力:xは5より大きい
}
他の言語との比較
言語 | 書き方 | Goでの対応 |
---|---|---|
C/Java | if (x > 5) { ... } | ❌ カッコは不要 |
Python | if x > 5: | ❌ 波カッコが必須 |
Go | if x > 5 { ... } | ✅ 正しい |
else と else if の使い方
func checkNumber(x int) {
if x > 0 {
fmt.Println("正の数です")
} else if x < 0 {
fmt.Println("負の数です")
} else {
fmt.Println("ゼロです")
}
}
実行例:
checkNumber(5) // 出力:正の数です
checkNumber(-3) // 出力:負の数です
checkNumber(0) // 出力:ゼロです
複雑な条件式
func checkAge(age int) {
if age >= 18 && age < 65 {
fmt.Println("働ける年齢です")
} else if age >= 65 {
fmt.Println("シニア世代です")
} else {
fmt.Println("未成年です")
}
}
論理演算子:
&&
:AND(両方がtrue)||
:OR(どちらかがtrue)!
:NOT(否定)
ポイント: Goのif
文は、カッコを使わず、波カッコは必須。基本はシンプルです。
Go独特の機能:if文の中で変数を定義する
変数初期化付きif文
Go言語では、if
文の中で変数の初期化と評価を同時に行うことができます。
基本構文:
if 変数 := 式; 条件 {
// 処理
}
具体例:
package main
import (
"fmt"
"math/rand"
)
func getRandomNumber() int {
return rand.Intn(100)
}
func main() {
if num := getRandomNumber(); num > 50 {
fmt.Printf("生成された数値 %d は50より大きい\n", num)
} else {
fmt.Printf("生成された数値 %d は50以下\n", num)
}
}
スコープ(変数の有効範囲)
重要なポイント:
num
のスコープはif文全体(else、else ifを含む)- if文の外では
num
は使えない
func example() {
if num := 10; num > 5 {
fmt.Println(num) // ✅ 使える
} else {
fmt.Println(num) // ✅ 使える(elseでも有効)
}
// fmt.Println(num) // ❌ エラー!if文の外では使えない
}
実用的な使用例
ファイル処理の例:
func readFile(filename string) {
if file, err := os.Open(filename); err != nil {
fmt.Printf("ファイルが開けません: %v\n", err)
} else {
defer file.Close()
fmt.Println("ファイルを正常に開きました")
// ここでfileを使った処理
}
}
文字列処理の例:
func checkString() {
text := "Hello, World!"
if length := len(text); length > 10 {
fmt.Printf("文字列は長い(%d文字)\n", length)
} else {
fmt.Printf("文字列は短い(%d文字)\n", length)
}
}
使いどころ
場面 | 例 |
---|---|
関数の戻り値をすぐ評価 | if result := calc(); result > 0 |
エラーハンドリング | if err := doSomething(); err != nil |
一時的な計算結果 | if sum := a + b; sum > 100 |
ポイント: Goでは、if文の条件の中で変数を定義できるという便利な特徴があります。
初心者がよくやるif文のミスとその対策
よくある間違い① 条件式にカッコをつけてしまう
❌ 間違った書き方(C/Java風):
if (x > 0) {
fmt.Println("正の数")
}
エラーメッセージ:
syntax error: unexpected (, expecting {
✅ 正しい書き方:
if x > 0 {
fmt.Println("正の数")
}
よくある間違い② 波カッコを省略する
❌ 間違った書き方:
if x > 0
fmt.Println("正の数") // エラー!
// または
if x > 0 fmt.Println("正の数") // エラー!
✅ 正しい書き方:
if x > 0 {
fmt.Println("正の数")
}
重要: Goでは波カッコは必須。1行でも省略できません。
よくある間違い③ elseの前に改行してしまう
❌ 間違った書き方:
if x > 0 {
fmt.Println("正")
}
else { // エラー!
fmt.Println("負")
}
エラーメッセージ:
syntax error: unexpected else, expecting }
✅ 正しい書き方:
if x > 0 {
fmt.Println("正")
} else { // 同じ行に書く
fmt.Println("負")
}
よくある間違い④ 変数のスコープを間違える
❌ 間違った使い方:
if num := 10; num > 5 {
fmt.Println("条件内:", num)
}
fmt.Println("条件外:", num) // エラー!numは存在しない
✅ 正しい使い方:
// パターン1:事前に変数を定義
num := 10
if num > 5 {
fmt.Println("条件内:", num)
}
fmt.Println("条件外:", num) // OK
// パターン2:if文内でのみ使用
if num := 10; num > 5 {
fmt.Println("条件内:", num)
// この中でのみnumを使用
}
間違いを避けるコツ
注意点 | 覚え方 |
---|---|
カッコ不要 | 「Goはシンプル、カッコいらず」 |
波カッコ必須 | 「1行でも波カッコは友達」 |
elseは同じ行 | 「elseは恥ずかしがり屋、離れたくない」 |
スコープに注意 | 「if文の中で生まれた変数は、if文の中で生涯を終える」 |
ポイント: Goのif文は見た目は簡単でも、細かい構文ミスが多発します。この決まりを覚えて慣れましょう。
実践!Goのif文活用テクニック
エラーハンドリングパターン
Goではエラー処理にif文を多用します。これはGoらしいコードスタイルです。
基本的なエラーハンドリング:
func divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("ゼロで割ることはできません")
}
return a / b, nil
}
func main() {
if result, err := divide(10, 2); err != nil {
fmt.Printf("エラー: %v\n", err)
} else {
fmt.Printf("結果: %d\n", result)
}
}
ファイル操作でのエラーハンドリング:
func readConfigFile() {
if data, err := os.ReadFile("config.txt"); err != nil {
log.Printf("設定ファイルが読めません: %v", err)
// デフォルト設定を使用
useDefaultConfig()
} else {
fmt.Printf("設定を読み込みました: %s\n", string(data))
}
}
文字列処理での活用
func processString(text string) {
// 文字列が空かチェック
if len(text) == 0 {
fmt.Println("空の文字列です")
return
}
// 特定の文字列を含むかチェック
if strings.Contains(text, "Go") {
fmt.Println("Go言語に関する内容です")
}
// 文字列の長さで処理を分岐
if length := len(text); length > 100 {
fmt.Printf("長い文章です(%d文字)\n", length)
} else {
fmt.Printf("短い文章です(%d文字)\n", length)
}
}
数値計算での活用
func calculateGrade(score int) string {
if score < 0 || score > 100 {
return "無効なスコアです"
}
if score >= 90 {
return "A"
} else if score >= 80 {
return "B"
} else if score >= 70 {
return "C"
} else if score >= 60 {
return "D"
} else {
return "F"
}
}
スライス・マップでの活用
func processSlice(numbers []int) {
// スライスが空かチェック
if len(numbers) == 0 {
fmt.Println("データがありません")
return
}
// 最初の要素をチェック
if first := numbers[0]; first > 0 {
fmt.Printf("最初の要素は正の数: %d\n", first)
}
}
func processMap(data map[string]int) {
// キーが存在するかチェック
if value, exists := data["score"]; exists {
fmt.Printf("スコア: %d\n", value)
} else {
fmt.Println("スコアが設定されていません")
}
}
HTTP処理での活用
func handleRequest(w http.ResponseWriter, r *http.Request) {
// HTTPメソッドをチェック
if r.Method != http.MethodPost {
http.Error(w, "POSTメソッドのみ対応", http.StatusMethodNotAllowed)
return
}
// リクエストボディをパース
if err := r.ParseForm(); err != nil {
http.Error(w, "フォームの解析に失敗", http.StatusBadRequest)
return
}
// パラメータの存在チェック
if name := r.FormValue("name"); name == "" {
http.Error(w, "nameパラメータが必要", http.StatusBadRequest)
return
} else {
fmt.Fprintf(w, "こんにちは、%sさん!", name)
}
}
設定値の検証
type Config struct {
Port int
Host string
Database string
}
func validateConfig(config Config) error {
if config.Port <= 0 || config.Port > 65535 {
return fmt.Errorf("無効なポート番号: %d", config.Port)
}
if config.Host == "" {
return fmt.Errorf("ホスト名が設定されていません")
}
if config.Database == "" {
return fmt.Errorf("データベース名が設定されていません")
}
return nil
}
ポイント: Goのif文は、戻り値の評価やエラー処理にとても役立ちます。
Goのif文のベストプラクティス
早期return(Early Return)を活用
❌ ネストが深い書き方:
func processUser(user User) error {
if user.Name != "" {
if user.Age >= 0 {
if user.Email != "" {
// 実際の処理
return saveUser(user)
} else {
return fmt.Errorf("メールアドレスが必要")
}
} else {
return fmt.Errorf("年齢は0以上である必要があります")
}
} else {
return fmt.Errorf("名前が必要")
}
}
✅ 早期returnでスッキリ:
func processUser(user User) error {
if user.Name == "" {
return fmt.Errorf("名前が必要")
}
if user.Age < 0 {
return fmt.Errorf("年齢は0以上である必要があります")
}
if user.Email == "" {
return fmt.Errorf("メールアドレスが必要")
}
// 実際の処理
return saveUser(user)
}
条件式を変数に分ける
❌ 複雑な条件式:
if user.Age >= 18 && user.HasLicense && user.ExperienceYears >= 2 && !user.HasViolations {
allowDriving(user)
}
✅ 意味のある変数名で分割:
isAdult := user.Age >= 18
hasValidLicense := user.HasLicense
hasEnoughExperience := user.ExperienceYears >= 2
hasCleanRecord := !user.HasViolations
if isAdult && hasValidLicense && hasEnoughExperience && hasCleanRecord {
allowDriving(user)
}
ゼロ値チェックの活用
// 文字列のゼロ値チェック
if name == "" {
// 空文字列の処理
}
// スライスのゼロ値チェック
if len(items) == 0 {
// 空スライスの処理
}
// ポインタのゼロ値チェック
if ptr == nil {
// nilポインタの処理
}
よくある質問と回答
Q: なぜGoはカッコが不要なのですか?
A: Goの設計思想「シンプルさ」のためです
Goは「読みやすく、書きやすく、理解しやすい」言語を目指しています。不要なカッコを省略することで、コードがすっきりし、可読性が向上します。
Q: 三項演算子(? :)は使えますか?
A: Goには三項演算子はありません
// ❌ 三項演算子(Goにはない)
result := x > 0 ? "positive" : "negative"
// ✅ if文を使う
var result string
if x > 0 {
result = "positive"
} else {
result = "negative"
}
Q: if文の中でbreak、continueは使えますか?
A: ループの中でのみ使用可能です
for i := 0; i < 10; i++ {
if i == 5 {
break // ✅ ループを抜ける
}
if i%2 == 0 {
continue // ✅ 次のループへ
}
fmt.Println(i)
}
Q: if文での型変換はどうしますか?
A: 型アサーションを使用します
func processInterface(v interface{}) {
if str, ok := v.(string); ok {
fmt.Printf("文字列: %s\n", str)
} else if num, ok := v.(int); ok {
fmt.Printf("整数: %d\n", num)
} else {
fmt.Println("未知の型")
}
}
まとめ:Goのif文を使いこなして、きれいなコードを書こう
今回学んだ重要なポイント:
- 構文の特徴:カッコ不要、波カッコ必須、elseは同じ行
- 変数初期化:if文の中で変数を定義できる便利機能
- スコープ:if文内で定義した変数は、if文内でのみ有効
- エラーハンドリング:Goらしいコーディングスタイル
- ベストプラクティス:早期return、条件式の分割
実際に使ってみよう:
- 基本的なif文から始めて構文に慣れる
- 変数初期化付きif文で短いコードを書いてみる
- エラーハンドリングパターンを実践してみる
- 早期returnでネストを減らしてみる
コメント