背景
最近、ファイルアップロードを追跡する Go スクリプトを書いていた時に壁にぶつかりました。読み込んだ 4,096 バイトと合計ファイルサイズの 2.5 GB を比較しようとしていました。Python や JavaScript の経験から、両方の値が明らかに整数なので、コンパイラが「うまくやってくれる」だろうと期待していました。しかし、ビルドは型不一致エラーですぐにクラッシュしました。
Go の型システムは妥協がありません。int と int64 のように、一見同じに見える数値型の間であっても、暗黙の型変換(強制)を行うことを拒否します。これらの変数を加算、減算、または比較しようとすると、コンパイラが拒絶反応を示します:
invalid operation: x + y (mismatched types int and int64)
デバッグプロセス
このエラーは通常、次のようなコードスニペットで発生します:
package main
import (
"fmt"
"os"
)
func main() {
var count int = 10
fileInfo, _ := os.Stat("data.csv")
size := fileInfo.Size() // これは int64 を返します
// ここでビルドが失敗します
if count < size {
fmt.Println("処理中...")
}
}
内部で何が起きているかを確認するには、fmt.Printf の %T 動詞を使用します。特定のライブラリ関数が何を返しているか確信が持てない時、これは救世主となります:
fmt.Printf("count の型: %T\n", count)
fmt.Printf("size の型: %T\n", size)
出力により競合が確認されます:
countは標準のintですsizeはint64です
解決策
Go は自動で橋渡しをしてくれないため、手動で型を合わせる必要があります。安全性の要件に応じて、主に 2 つの戦略があります。
オプション 1:小さい方の型を int64 にキャストする(推奨)
ほとんどの場合、これが最善の策です。標準の int を int64 に変換するのは、ターゲットのコンテナの方が大きいため安全です。オーバーフローのバグが発生するリスクはありません。
if int64(count) < size {
fmt.Println("int64 キャストで修正済み")
}
オプション 2:int64 を int にキャストする
これは控えめに使用してください。64 ビットシステムでは int は 64 ビット幅ですが、32 ビットシステムでは 32 ビットしかありません。巨大な int64 のファイルサイズ(5 GB など)を 32 ビットの int にキャストすると、値が切り捨てられます。これにより、追跡が非常に困難なロジックバグが発生します。
if count < int(size) {
fmt.Println("int キャストで修正済み")
}
定数のロジック
count が int64 であっても、count < 100 は問題なくコンパイルできることに気づくかもしれません。これは、Go の型のない定数がコンテキストを認識するためです。定数は比較対象の変数の型を採用します。エラーが発生するのは、演算の両側がすでに特定の「型付き」変数として固定されている場合のみです。
検証
修正を検証するため、ロジックを更新して go run main.go を実行しました。型が一致していれば、コンパイラは沈黙し、バイナリが実行されます。また、浮動小数点演算が期待通りに機能することを確認するため、簡単なパーセンテージチェックを追加しました。
// 最終的な検証済みコード
package main
import "fmt"
func main() {
var processed int = 500
var total int64 = 1024
// 混合計算には明示的なキャストを使用する
percentage := float64(processed) / float64(total) * 100
fmt.Printf("進捗: %.2f%%\n", percentage)
if int64(processed) != total {
fmt.Println("ステータス: 未完了")
}
}
学んだ教訓
- 厳格さは安全性に直結する: 明示的なキャストを強制することで、Go は C++ や JavaScript の開発者を悩ませる静かなオーバーフローバグを防ぎます。
- int64 に標準化する: ファイルサイズ、データベース ID、またはタイムスタンプを扱う際、煩わしいキャストを最小限に抑えるために、現在はグローバルで
int64を使用するようにしています。 - 戻り値の型に注意する:
len()のような標準関数はintを返しますが、os.FileInfo.Size()はint64を返します。この違いを念頭に置くことで、ビルドエラーを未然に防ぐことができます。

