将2个值存储在一个变量中

Is this Go code correct and portable, I need to store 2 counters (each call only one counter will be updated) in one variable to avoid locks in actual code where I am going to use single atomic.AddUint64() instead of locking whole struct.

package main

import "fmt"

var long uint64 // Actual counters storage

func main() {
    left := uint32(100) // First counter
    right := uint32(200) // Second counter
    long = uint64(left)
    long = long << 32 | uint64(right)
    fmt.Println(left, right)

    long += uint64(1 << 32) // Increment left
    long += 1 // Increment right

    xLeft := uint32(long >> 32) // Get left
    xRight := uint32(long) // Get right
    fmt.Println(xLeft, xRight)
}

http://play.golang.org/p/aBlp-Zatgn

Is this Go code correct and portable

It is correct, as long as you work with unsigned integers of 64-bit width.

Portability in this case is provided by the sync/atomic packages to the architectures supported by the Go compiler. Note, however, that not all architectures support "true" atomic operations on 64-bit wide data. For example, the i386 implementation uses a CAS-loop:

TEXT ·AddUint64(SB),NOSPLIT,$0-20
    // no XADDQ so use CMPXCHG8B loop
    MOVL    addr+0(FP), BP
    TESTL   $7, BP
    JZ  2(PC)
    MOVL    0, AX // crash with nil ptr deref
    // DI:SI = delta
    MOVL    delta_lo+4(FP), SI
    MOVL    delta_hi+8(FP), DI
    // DX:AX = *addr
    MOVL    0(BP), AX
    MOVL    4(BP), DX
addloop:
    // CX:BX = DX:AX (*addr) + DI:SI (delta)
    MOVL    AX, BX
    MOVL    DX, CX
    ADDL    SI, BX
    ADCL    DI, CX

    // if *addr == DX:AX {
    //  *addr = CX:BX
    // } else {
    //  DX:AX = *addr
    // }
    // all in one instruction
    LOCK
    CMPXCHG8B   0(BP)

    JNZ addloop

    // success
    // return CX:BX
    MOVL    BX, new_lo+12(FP)
    MOVL    CX, new_hi+16(FP)
    RET

That may open the question: why not use a struct with a lock?


Edit to answer question in comments: Yes, using a 32-bit integer would result in actual atomic operations on all Go-supported architectures because they all support XADDL (or analog) to the best of my knowledge.