missing return at end of function の原因と直し方
戻り値のある関数は、すべての実行経路の末尾でreturn文が必要です。if文の片方の分岐にしかreturnが無いと、関数全体の末尾に到達しうると判断されエラーになります。
エラーメッセージの読み方
./main.go:10:1: missing return
./main.go- ファイル名
10- 行番号
1- 列番号
missing return- 詳細メッセージ — 何が問題だったか
このエラーが出る典型パターン
パターン1
1 package main 2 3 import "fmt" 4 5 func abs(x int) int { 6 if x < 0 { 7 return -x 8 } 9 ^ 10 } 11 12 func main() { 13 fmt.Println(abs(-5)) 14 }
ifブロックにしかreturnが無いため、x >= 0の場合に関数が値を返さずに終わってしまいます。elseに相当する戻り値が必要です。
直し方: (空) を return x にします。
パターン2
1 package main 2 3 import "fmt" 4 5 func classify(x int) string { 6 if x < 0 { 7 return "negative" 8 } 9 ^ 10 } 11 12 func main() { 13 fmt.Println(classify(-5)) 14 }
x < 0の場合以外の戻り値が書かれていないため、コンパイラは関数の末尾に到達しうると判定します。
直し方: (空) を return "non-negative" にします。
パターン3
1 package main 2 3 import "fmt" 4 5 func bigger(a, b int) int { 6 if a > b { 7 return a 8 } 9 ^ 10 } 11 12 func main() { 13 fmt.Println(bigger(3, 7)) 14 }
a > bでない場合(bの方が大きいか同じ場合)のreturnが無いため、関数の末尾に到達する経路が残ります。
直し方: (空) を return b にします。
パターン4
1 package main 2 3 import "fmt" 4 5 func sign(x int) int { 6 if x > 0 { 7 return 1 8 } 9 ^ 10 } 11 12 func main() { 13 fmt.Println(sign(-5)) 14 }
x <= 0の場合の戻り値が書かれていないため、コンパイラは関数末尾への到達を許してしまいます。
直し方: (空) を return -1 にします。
パターン5
1 package main 2 3 import "fmt" 4 5 func describe(n int) string { 6 if n == 0 { 7 return "zero" 8 } 9 ^ 10 } 11 12 func main() { 13 fmt.Println(describe(5)) 14 }
n == 0以外のケースのreturnが抜けているため、関数がstring型の値を返さずに終わりうる経路が残ります。
直し方: (空) を return "nonzero" にします。
よくある誤解
「if-elseで両方のケースを網羅していれば、コンパイラはreturnが漏れなく通ることを理解してくれるはず」という思い込みは誤りです。Goの到達可能性解析は限定的で、elseを省略したif文の外側に明示的なreturnが無いと、その関数は末尾に到達しうると判定されます。
実務での勘所
Goの到達可能性の判定は、意図的に単純なルールに留められています。Go言語仕様には「終端する文(terminating statement)」の条件が明示的に列挙されており、if文はelse節を伴い、両方の分岐が終端する場合に限って全体が終端すると判定されます。より賢い解析をすれば救えるはずのコードでもこの単純なルールでは弾かれることがありますが、Goはルールを複雑にして稀なケースを救うより、誰もが仕様を読めば挙動を正確に予測できる単純さを優先しています。