go-reader - 解説

実装の詳細解説

バッファ管理のポイント

// グローバルなバッファマップ
var fdBuffers = make(map[int][]byte)

複数のファイルディスクリプタを同時に扱うため、各fdに対応するバッファをマップで管理します。

改行検索のアルゴリズム

for i, b := range buffer {
    if b == '\n' {
        line := string(buffer[:i+1])  // 改行を含む
        fdBuffers[fd] = buffer[i+1:]   // 残りを保持
        return line, nil
    }
}

バッファを線形探索して改行文字を見つけます。見つかったら:

  • 改行までを返り値として返す
  • 改行以降をバッファに保持

EOF 処理

if err != nil || n == 0 {
    if len(buffer) > 0 {
        line := string(buffer)
        fdBuffers[fd] = nil
        return line, nil
    }
    return "", io.EOF
}

ファイル末尾に達したとき:

  • バッファに残りがあれば返す(改行なしの最終行)
  • なければ io.EOF を返す
  • よくある間違い

    1. バッファのクリア忘れ

    // 間違い: バッファをクリアしない
    delete(fdBuffers, fd)  // これを忘れるとメモリリーク
    

    2. 改行を含めない

    // 間違い
    line := string(buffer[:i])  // 改行を含まない
    
    // 正しい
    line := string(buffer[:i+1])  // 改行を含む
    

    最適化のヒント

  • バッファサイズ: ファイルサイズに応じて調整
  • メモリプール: sync.Pool でバッファを再利用
  • mmap: 大きなファイルはメモリマップを検討