在go中将int32转换为字节数组

Kug*_*men 10 go

我正在使用big.NewInt(int64(e)).Bytes()将int32转换为字节数组.有没有更优雅的方式来做到这一点?

我希望AQAB是e的base64编码值

http://play.golang.org/p/M46X7OpZpu

const e = 65537

func base64Encode(b []byte) string {
  return strings.TrimRight(base64.StdEncoding.EncodeToString(b), "=")
}

func main() {
  fmt.Printf("exp %d\n", e)

  b := make([]byte, 4)
  binary.BigEndian.PutUint32(b, e)
  fmt.Printf("b: BigEndian.PutUint32 %x (Bad) %s\n", b, base64Encode(b))

  b2 := make([]byte, 4)
  binary.BigEndian.PutUint32(b2, e)
  for i := range b2 {
    if b2[i] != 0 {
    b2 = b2[i:]
    break
     }
  }
  fmt.Printf("b2: BigEndian.PutUint32 %x (Good) %s\n", b2, base64Encode(b2))

  b4 := big.NewInt(int64(e)).Bytes()
  fmt.Printf("b4: big.NewInt(int64(e)).Bytes() %x (Good) %s\n", b4, base64Encode(b4))
}
Run Code Online (Sandbox Code Playgroud)

输出:

exp 65537
b: BigEndian.PutUint32 00010001 (Bad) AAEAAQ
b2: BigEndian.PutUint32 010001 (Good) AQAB
b4: big.NewInt(int64(e)).Bytes() 010001 (Good) AQAB

exp 1
b: BigEndian.PutUint32 00000001 (Bad) AAAAAQ
b2: BigEndian.PutUint32 01 (Good) AQ
b4: big.NewInt(int64(e)).Bytes() 01 (Good) AQ

exp 1000000
b: BigEndian.PutUint32 000f4240 (Bad) AA9CQA
b2: BigEndian.PutUint32 0f4240 (Good) D0JA
b4: big.NewInt(int64(e)).Bytes() 0f4240 (Good) D0JA
Run Code Online (Sandbox Code Playgroud)

编辑:

我已经对b2和b4进行了基准测试:

b2  1000000000          68.1 ns/op         8 B/op          1 allocs/op
b4  200000000          248 ns/op          90 B/op          3 allocs/op
Run Code Online (Sandbox Code Playgroud)

我现在要用b2 ......

voi*_*gic 5

对于这种任务,我认为你的第一个选择应该始终使用encoding/binary,如果这不足,则按位数学.但是,在某些情况下,复制数据的开销太大或者这些安全的解决方案太慢:

虽然我不会称之为优雅,但您可以使用Go unsafereflect*软件包来快速完成此操作.请记住,这不会复制数据; 相反,它只是给你另一个"视图".并且不安全意味着你需要非常小心 - (你好单元测试和代码审查)并记住你打破了Go的内存安全性.然而,当执行速度是主要关注点并且你的团队同意unsafe是有道理的时候,unsafe很少会被击败.

const BYTES_IN_INT32 = 4

func UnsafeCaseInt32ToBytes(val int32) []byte {
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&val)), Len: BYTES_IN_INT32, Cap: BYTES_IN_INT32}
    return *(*[]byte)(unsafe.Pointer(&hdr))
}

func UnsafeCastInt32sToBytes(ints []int32) []byte {        
    length := len(ints) * BYTES_IN_INT32
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&ints[0])), Len: length, Cap: length}
    return *(*[]byte)(unsafe.Pointer(&hdr))
}
Run Code Online (Sandbox Code Playgroud)

*注意:您可能想要使用SizeOf而不是常量.我更喜欢恒久.

更新:以下是一些基准测试结果:

BenchmarkB2     20000000     88.7  ns/op
BenchmarkB4     5000000     309    ns/op
BenchmarkUnsafe 1000000000    2.25 ns/op
Run Code Online (Sandbox Code Playgroud)

  • 不,换班是安全的.无论字节顺序如何,`x >> 24`将得到`x`的高阶8位. (7认同)
  • "不安全"不仅打破了内存安全性,还引入了字节序问题. (5认同)
  • @voidlogic:使用适当的掩码将字节与32位数字隔离开来也是字节序独立的.另外,OP问题不是询问[] int32 - > []字节,而是int32 - > []字节,所以我猜你的答案是无效的.(-1) (4认同)
  • 一个可怕且不必要的解决方案. (4认同)
  • @peterSO你怎么能说甚至不知道用户的用例?不安全也是可以避免的,这并不意味着它永远无效.它不像我省略了使用它的常见警告. (2认同)