assignment mismatch: 1 variable but ... returns 2 values の原因と直し方
複数の戻り値を持つ関数の結果を、1つの変数だけで受け取ろうとするとコンパイルエラーになります。errorを返す関数を呼ぶときに特に起きやすいミスです。
エラーメッセージの読み方
./main.go:9:7: assignment mismatch: 1 variable but strconv.Atoi returns 2 values
./main.go- ファイル名
9- 行番号
7- 列番号
assignment mismatch: 1 variable but strconv.Atoi returns 2 values- 詳細メッセージ — 何が問題だったか
このエラーが出る典型パターン
パターン1
1 package main 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 func main() { 9 n := strconv.Atoi("5") ^ 10 fmt.Println(n, err) 11 }
strconv.Atoiは変換結果とerrorの2つを返します。1つの変数だけで受け取ることはできません。
直し方: n を n, err にします。
パターン2
1 package main 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 func main() { 9 n := strconv.ParseBool("true") ^ 10 fmt.Println(n, err) 11 }
ParseBoolもbool値とerrorの2つを返すため、受け取る変数を2つ用意する必要があります。
直し方: n を n, err にします。
パターン3
1 package main 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 func main() { 9 n := strconv.ParseFloat("3.14", 64) ^ 10 fmt.Println(n, err) 11 }
ParseFloatも同様にfloat64とerrorの2値を返す関数です。
直し方: n を n, err にします。
パターン4
1 package main 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 func main() { 9 n := strconv.ParseInt("42", 10, 64) ^ 10 fmt.Println(n, err) 11 }
ParseIntはint64とerrorの2値を返すため、変数を1つだけ用意しても受け取りきれません。
直し方: n を n, err にします。
パターン5
1 package main 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 func main() { 9 n := strconv.Unquote("\"hi\"") ^ 10 fmt.Println(n, err) 11 }
Unquoteもstringとerrorの2値を返すため、他の複数戻り値の関数と同じ対応が必要です。
直し方: n を n, err にします。
よくある誤解
「戻り値の一部だけ受け取りたいなら、変数を1つだけ書けば残りは無視されるはず」という思い込みは誤りです。Goでは戻り値の個数と受け取る変数の個数を完全に一致させる必要があり、不要な値も_で明示的に受け取らなければなりません。
実務での勘所
Goの複数戻り値は、PythonやRustのタプルのように「2つの値をまとめた1つの値」として存在しているわけではありません。Goは意図的にタプル型を言語に追加しておらず、複数の戻り値は代入文やreturn文というごく限られた構文の位置でだけ意味を持つ、特別な扱いです。そのため「戻り値をまとめて1つの変数に入れる」という発想自体が成立せず、必ず戻り値の数だけ受け皿の変数を用意する(不要なものは_で捨てる)必要があります。これは厳しいルールというより、複数の値をひとまとめにする型がGoにそもそも存在しないことの帰結です。