Go/uint64
Goのuint64について
Goにおけるuint64
は64ビット符号なし整数型を表す組み込み型です。8バイトのサイズを持ち、0から18446744073709551615までの値を格納できます。
基本情報
uint64
は64ビット(8バイト)の符号なし整数型- 値の範囲: 0 から 18446744073709551615 (2^64-1)
- メモリ上での表現: 64ビット
- 大容量データサイズ、高精度タイムスタンプ、一意ID生成などに使用される
他のキーワードとの組み合わせ
変数宣言との組み合わせ
var totalBytes uint64 = 1099511627776 // 1TB count := uint64(1000000000) // 型推論による短縮形 maxValue := uint64(18446744073709551615)
定数定義との組み合わせ
const BYTES_PER_KB uint64 = 1024 const BYTES_PER_MB uint64 = 1024 * 1024 const BYTES_PER_GB uint64 = 1024 * 1024 * 1024 const BYTES_PER_TB uint64 = 1024 * 1024 * 1024 * 1024 const NANOSECONDS_PER_SECOND uint64 = 1000000000
関数パラメータと戻り値
func calculateTotalSize(files []FileInfo) uint64 { var total uint64 for _, file := range files { total += file.Size } return total } func getCurrentNanoseconds() uint64 { return uint64(time.Now().UnixNano()) }
型変換
i := 1000000000000 size := uint64(i) // int から uint64 への変換 f := 3.14159265359e12 rounded := uint64(f) // float から uint64 への変換(小数点以下切り捨て) // 時間関連の変換 duration := time.Minute nanos := uint64(duration.Nanoseconds())
配列とスライス
var timestamps [1000]uint64 // uint64型の固定長配列 buffer := make([]uint64, 10000) // uint64型のスライス sizes := []uint64{1073741824, 2147483648, 4294967296} // GB単位のサイズ
マップ
fileSizes := make(map[string]uint64) fileSizes["large_dataset.csv"] = 10737418240 // 10GB fileSizes["backup.tar.gz"] = 53687091200 // 50GB userIDs := make(map[uint64]string) userIDs[1234567890123456789] = "user@example.com"
構造体のフィールド
type StorageInfo struct { DeviceName string TotalSpace uint64 // バイト単位 UsedSpace uint64 FreeSpace uint64 InodeCount uint64 } type LogEntry struct { ID uint64 // 一意識別子 Timestamp uint64 // ナノ秒精度のタイムスタンプ UserID uint64 EventSize uint64 // バイト単位 }
ビット操作
var flags uint64 = 0 // ビットをセット flags |= 1 << 32 // ビットをクリア flags &^= 1 << 16 // ビットをチェック if (flags & (1 << 32)) != 0 { fmt.Println("32番目のビットがセットされています") } // 64ビットを8つの8ビットに分割 var value uint64 = 0x123456789ABCDEF0 bytes := [8]uint8{ uint8(value >> 56), uint8(value >> 48), uint8(value >> 40), uint8(value >> 32), uint8(value >> 24), uint8(value >> 16), uint8(value >> 8), uint8(value), }
一般的なユースケース
- 大容量ストレージ管理
type DiskUsage struct { Path string TotalBytes uint64 UsedBytes uint64 FreeBytes uint64 } func GetDiskUsage(path string) (DiskUsage, error) { var stat syscall.Statfs_t err := syscall.Statfs(path, &stat) if err != nil { return DiskUsage{}, err } total := uint64(stat.Blocks) * uint64(stat.Bsize) free := uint64(stat.Bavail) * uint64(stat.Bsize) used := total - free return DiskUsage{ Path: path, TotalBytes: total, UsedBytes: used, FreeBytes: free, }, nil } func FormatBytes(bytes uint64) string { const unit = 1024 if bytes < unit { return fmt.Sprintf("%d B", bytes) } div, exp := uint64(unit), 0 for n := bytes / unit; n >= unit; n /= unit { div *= unit exp++ } return fmt.Sprintf("%.2f %ciB", float64(bytes)/float64(div), "KMGTPE"[exp]) }
- 高精度タイムスタンプ
type HighPrecisionEvent struct { ID uint64 Name string TimestampNanos uint64 // ナノ秒精度 DurationNanos uint64 } func NewEvent(name string) HighPrecisionEvent { return HighPrecisionEvent{ ID: generateEventID(), Name: name, TimestampNanos: uint64(time.Now().UnixNano()), } } func (e *HighPrecisionEvent) Finish() { endTime := uint64(time.Now().UnixNano()) e.DurationNanos = endTime - e.TimestampNanos } func (e HighPrecisionEvent) ToTime() time.Time { return time.Unix(0, int64(e.TimestampNanos)) } func (e HighPrecisionEvent) GetDuration() time.Duration { return time.Duration(e.DurationNanos) } // ベンチマーク用途での使用例 func BenchmarkFunction(fn func()) (uint64, error) { start := uint64(time.Now().UnixNano()) fn() end := uint64(time.Now().UnixNano()) return end - start, nil }
- 一意ID生成(Snowflake ID パターン)
import ( "sync" "time" ) type SnowflakeIDGenerator struct { mutex sync.Mutex epoch uint64 // カスタムエポック (ミリ秒) nodeID uint64 // ノードID (10ビット) sequence uint64 // シーケンス番号 (12ビット) lastTime uint64 // 最後に生成した時刻 } func NewSnowflakeIDGenerator(nodeID uint64) *SnowflakeIDGenerator { // 2020年1月1日をカスタムエポックとする epoch := uint64(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli()) return &SnowflakeIDGenerator{ epoch: epoch, nodeID: nodeID & 0x3FF, // 10ビットに制限 } } func (g *SnowflakeIDGenerator) Generate() (uint64, error) { g.mutex.Lock() defer g.mutex.Unlock() now := uint64(time.Now().UnixMilli()) if now < g.lastTime { return 0, fmt.Errorf("clock moved backwards") } if now == g.lastTime { g.sequence = (g.sequence + 1) & 0xFFF // 12ビットに制限 if g.sequence == 0 { // シーケンスがオーバーフローした場合、次のミリ秒まで待機 for now <= g.lastTime { now = uint64(time.Now().UnixMilli()) } } } else { g.sequence = 0 } g.lastTime = now // ID構成: 1ビット(予約) + 41ビット(時刻) + 10ビット(ノードID) + 12ビット(シーケンス) id := ((now - g.epoch) << 22) | (g.nodeID << 12) | g.sequence return id, nil } func (g *SnowflakeIDGenerator) ParseID(id uint64) (timestamp time.Time, nodeID uint64, sequence uint64) { ms := (id >> 22) + g.epoch timestamp = time.UnixMilli(int64(ms)) nodeID = (id >> 12) & 0x3FF sequence = id & 0xFFF return }
- 大容量データ処理とカウンター
type DataProcessor struct { RecordsProcessed uint64 BytesProcessed uint64 ErrorCount uint64 StartTime uint64 } func NewDataProcessor() *DataProcessor { return &DataProcessor{ StartTime: uint64(time.Now().UnixNano()), } } func (dp *DataProcessor) ProcessRecord(data []byte) error { // データ処理のシミュレーション if len(data) == 0 { dp.ErrorCount++ return fmt.Errorf("empty data") } dp.RecordsProcessed++ dp.BytesProcessed += uint64(len(data)) return nil } func (dp *DataProcessor) GetStatistics() map[string]interface{} { currentTime := uint64(time.Now().UnixNano()) elapsedNanos := currentTime - dp.StartTime elapsedSeconds := float64(elapsedNanos) / float64(time.Second) recordsPerSecond := float64(dp.RecordsProcessed) / elapsedSeconds bytesPerSecond := float64(dp.BytesProcessed) / elapsedSeconds return map[string]interface{}{ "records_processed": dp.RecordsProcessed, "bytes_processed": FormatBytes(dp.BytesProcessed), "error_count": dp.ErrorCount, "elapsed_seconds": elapsedSeconds, "records_per_sec": recordsPerSecond, "bytes_per_sec": FormatBytes(uint64(bytesPerSecond)), "error_rate": float64(dp.ErrorCount) / float64(dp.RecordsProcessed), } }
- ハッシュ値と暗号学的処理
import ( "crypto/sha256" "encoding/binary" "hash/fnv" ) func Hash64FNV(data []byte) uint64 { h := fnv.New64a() h.Write(data) return h.Sum64() } func Hash64SHA256(data []byte) uint64 { hash := sha256.Sum256(data) // SHA256の最初の8バイトを取得 return binary.BigEndian.Uint64(hash[:8]) } type BloomFilter struct { bitArray []bool size uint64 hashFuncs []func([]byte) uint64 } func NewBloomFilter(size uint64, hashCount int) *BloomFilter { return &BloomFilter{ bitArray: make([]bool, size), size: size, hashFuncs: []func([]byte) uint64{ Hash64FNV, Hash64SHA256, }, } } func (bf *BloomFilter) Add(data []byte) { for _, hashFunc := range bf.hashFuncs { index := hashFunc(data) % bf.size bf.bitArray[index] = true } } func (bf *BloomFilter) MightContain(data []byte) bool { for _, hashFunc := range bf.hashFuncs { index := hashFunc(data) % bf.size if !bf.bitArray[index] { return false } } return true }
- ネットワーク統計とトラフィック監視
type NetworkInterface struct { Name string BytesSent uint64 BytesRecv uint64 PacketsSent uint64 PacketsRecv uint64 ErrorsSent uint64 ErrorsRecv uint64 LastUpdated uint64 } type TrafficMonitor struct { interfaces map[string]*NetworkInterface startTime uint64 } func NewTrafficMonitor() *TrafficMonitor { return &TrafficMonitor{ interfaces: make(map[string]*NetworkInterface), startTime: uint64(time.Now().UnixNano()), } } func (tm *TrafficMonitor) UpdateInterface(name string, bytesSent, bytesRecv, packetsSent, packetsRecv uint64) { iface, exists := tm.interfaces[name] if !exists { iface = &NetworkInterface{Name: name} tm.interfaces[name] = iface } iface.BytesSent = bytesSent iface.BytesRecv = bytesRecv iface.PacketsSent = packetsSent iface.PacketsRecv = packetsRecv iface.LastUpdated = uint64(time.Now().UnixNano()) } func (tm *TrafficMonitor) GetTotalTraffic() (uint64, uint64) { var totalSent, totalRecv uint64 for _, iface := range tm.interfaces { totalSent += iface.BytesSent totalRecv += iface.BytesRecv } return totalSent, totalRecv } func (tm *TrafficMonitor) GetBandwidthUsage(interfaceName string) (float64, float64) { iface, exists := tm.interfaces[interfaceName] if !exists { return 0, 0 } elapsedNanos := uint64(time.Now().UnixNano()) - tm.startTime elapsedSeconds := float64(elapsedNanos) / float64(time.Second) sentPerSecond := float64(iface.BytesSent) / elapsedSeconds recvPerSecond := float64(iface.BytesRecv) / elapsedSeconds return sentPerSecond, recvPerSecond }
- データベース/キーバリューストア
type KeyValueStore struct { data map[uint64][]byte nextKey uint64 totalSize uint64 maxSize uint64 accessCount uint64 } func NewKeyValueStore(maxSize uint64) *KeyValueStore { return &KeyValueStore{ data: make(map[uint64][]byte), nextKey: 1, maxSize: maxSize, } } func (kvs *KeyValueStore) Put(value []byte) (uint64, error) { valueSize := uint64(len(value)) if kvs.totalSize+valueSize > kvs.maxSize { return 0, fmt.Errorf("insufficient space") } key := kvs.nextKey kvs.data[key] = make([]byte, len(value)) copy(kvs.data[key], value) kvs.totalSize += valueSize kvs.nextKey++ return key, nil } func (kvs *KeyValueStore) Get(key uint64) ([]byte, error) { kvs.accessCount++ value, exists := kvs.data[key] if !exists { return nil, fmt.Errorf("key not found") } result := make([]byte, len(value)) copy(result, value) return result, nil } func (kvs *KeyValueStore) Delete(key uint64) error { value, exists := kvs.data[key] if !exists { return fmt.Errorf("key not found") } kvs.totalSize -= uint64(len(value)) delete(kvs.data, key) return nil } func (kvs *KeyValueStore) GetStats() map[string]uint64 { return map[string]uint64{ "total_keys": uint64(len(kvs.data)), "total_size": kvs.totalSize, "max_size": kvs.maxSize, "access_count": kvs.accessCount, "next_key": kvs.nextKey, } }
- バイナリファイル処理とシリアライゼーション
import ( "encoding/binary" "io" ) type LargeFileHeader struct { Magic uint64 Version uint64 FileSize uint64 RecordCount uint64 Timestamp uint64 Checksum uint64 } func (h LargeFileHeader) WriteTo(w io.Writer) error { return binary.Write(w, binary.LittleEndian, h) } func ReadLargeFileHeader(r io.Reader) (LargeFileHeader, error) { var header LargeFileHeader err := binary.Read(r, binary.LittleEndian, &header) return header, err } type LargeFileReader struct { file io.ReadSeeker header LargeFileHeader currentPos uint64 recordSize uint64 } func NewLargeFileReader(file io.ReadSeeker, recordSize uint64) (*LargeFileReader, error) { header, err := ReadLargeFileHeader(file) if err != nil { return nil, err } return &LargeFileReader{ file: file, header: header, currentPos: 0, recordSize: recordSize, }, nil } func (lfr *LargeFileReader) ReadRecord(index uint64) ([]byte, error) { if index >= lfr.header.RecordCount { return nil, fmt.Errorf("index out of range") } offset := int64(binary.Size(lfr.header)) + int64(index*lfr.recordSize) _, err := lfr.file.Seek(offset, io.SeekStart) if err != nil { return nil, err } record := make([]byte, lfr.recordSize) _, err = io.ReadFull(lfr.file, record) if err != nil { return nil, err } return record, nil } func (lfr *LargeFileReader) GetRecordCount() uint64 { return lfr.header.RecordCount }
注意点
- オーバーフロー: 最大値(18446744073709551615)を超えると、0に戻ります
var x uint64 = 18446744073709551615 x++ // x は 0 になる // オーバーフロー対策 func safeAdd64(a, b uint64) (uint64, bool) { if a > 18446744073709551615-b { return 0, false // オーバーフロー } return a + b, true } // 大きな数値の安全な演算 func safeMul64(a, b uint64) (uint64, bool) { if a == 0 || b == 0 { return 0, true } if a > 18446744073709551615/b { return 0, false // オーバーフロー } return a * b, true }
- パフォーマンスの考慮: 32ビットシステムでは64ビット演算が遅い場合があります
import "runtime" func chooseIDType() { if runtime.GOARCH == "386" || runtime.GOARCH == "arm" { // 32ビットシステムではuint32の使用を検討 fmt.Println("32-bit system detected, consider using uint32 for better performance") } }
- JSON/XMLシリアライゼーション: JavaScriptの数値精度の制限に注意
import ( "encoding/json" "strconv" ) type BigNumber struct { Value uint64 } // カスタムJSON marshaling func (bn BigNumber) MarshalJSON() ([]byte, error) { // JavaScriptの安全な整数範囲を超える場合は文字列として送信 if bn.Value > 9007199254740991 { // 2^53 - 1 return json.Marshal(strconv.FormatUint(bn.Value, 10)) } return json.Marshal(bn.Value) } func (bn *BigNumber) UnmarshalJSON(data []byte) error { var str string if err := json.Unmarshal(data, &str); err == nil { value, err := strconv.ParseUint(str, 10, 64) if err != nil { return err } bn.Value = value return nil } return json.Unmarshal(data, &bn.Value) }
- atomic操作: 並行アクセス時は原子的操作を使用
import "sync/atomic" type AtomicCounter struct { value uint64 } func (ac *AtomicCounter) Increment() uint64 { return atomic.AddUint64(&ac.value, 1) } func (ac *AtomicCounter) Get() uint64 { return atomic.LoadUint64(&ac.value) } func (ac *AtomicCounter) Set(value uint64) { atomic.StoreUint64(&ac.value, value) } func (ac *AtomicCounter) CompareAndSwap(old, new uint64) bool { return atomic.CompareAndSwapUint64(&ac.value, old, new) }
- 時間精度: ナノ秒精度を活用する際の注意点
func measureHighPrecision(fn func()) time.Duration { start := time.Now() fn() end := time.Now() // ナノ秒精度での測定 return end.Sub(start) } // システムクロックの精度確認 func checkClockResolution() { var prev uint64 var count int start := time.Now() for time.Since(start) < time.Millisecond { current := uint64(time.Now().UnixNano()) if current != prev { count++ prev = current } } fmt.Printf("Clock resolution: approximately %d nanoseconds\n", int(time.Millisecond.Nanoseconds())/count) }
uint64型は、大容量データ処理、高精度タイミング、一意ID生成、ネットワーク統計など、非常に大きな数値を扱う場面で威力を発揮します。ただし、オーバーフローやパフォーマンス、プラットフォーム間の互換性には十分注意して使用することが重要です。
カテゴリ:Go