将整数转换为字节数组

问题描述 投票:0回答:12

我有一个接收

[]byte
的函数,但我拥有的是
int
,进行此转换的最佳方法是什么?

err = a.Write([]byte(myInt))

我想我可以走很长的路,把它变成一个字符串,然后把它放入字节中,但这听起来很难看,我想有更好的方法来做到这一点。

go type-conversion
12个回答
79
投票

我同意 Brainstorm 的方法:假设您正在传递机器友好的二进制表示,请使用

encoding/binary
库。 OP 表明
binary.Write()
可能会产生一些开销。查看Write()实现的
源代码
,我发现它做了一些运行时决策以实现最大的灵活性。

func Write(w io.Writer, order ByteOrder, data interface{}) error {
    // Fast path for basic types.
    var b [8]byte
    var bs []byte
    switch v := data.(type) {
    case *int8:
        bs = b[:1]
        b[0] = byte(*v)
    case int8:
        bs = b[:1]
        b[0] = byte(v)
    case *uint8:
        bs = b[:1]
        b[0] = *v
    ...

对吗? Write() 接受一个非常通用的

data
第三个参数,这会带来一些开销,因为 Go 运行时被迫编码类型信息。由于
Write()
在这里做了一些运行时决策,您在您的情况下根本不需要这些决策,也许您可以直接调用编码函数并查看它是否表现更好。

类似这样的:

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    bs := make([]byte, 4)
    binary.LittleEndian.PutUint32(bs, 31415926)
    fmt.Println(bs)
}

让我们知道它的表现如何。

否则,如果您只是想获取整数的 ASCII 表示形式,则可以获取字符串表示形式(可能使用

strconv.Itoa
)并将该字符串转换为
[]byte
类型。

package main

import (
    "fmt"
    "strconv"
)

func main() {
    bs := []byte(strconv.Itoa(31415926))
    fmt.Println(bs)
}

35
投票

查看“编码/二进制”包。特别是ReadWrite功能:

binary.Write(a, binary.LittleEndian, myInt)

27
投票

抱歉,这可能有点晚了。但我认为我在 go 文档中找到了更好的实现。

buf := new(bytes.Buffer)
var num uint16 = 1234
err := binary.Write(buf, binary.LittleEndian, num)
if err != nil {
    fmt.Println("binary.Write failed:", err)
}
fmt.Printf("% x", buf.Bytes())

3
投票

我认为 int 类型有任何方法可以将 int 哈希转换为字节,但首先我找到了 math / big 方法 https://golang.org/pkg/math/big/

var f int = 52452356235;          // int
var s = big.NewInt(int64(f))      // int to big Int
var b = s.Bytes()                 // big Int to bytes
// b - byte slise
var r = big.NewInt(0).SetBytes(b) // bytes to big Int
var i int = int(r.Int64())        // big Int to int

https://play.golang.org/p/VAKSGw8XNQq

但是,该方法使用绝对值。 如果多花1个字节,就可以转移符号

func IntToBytes(i int) []byte{
    if i > 0 {
        return append(big.NewInt(int64(i)).Bytes(), byte(1))
    }
    return append(big.NewInt(int64(i)).Bytes(), byte(0))
}
func BytesToInt(b []byte) int{
    if b[len(b)-1]==0 {
        return -int(big.NewInt(0).SetBytes(b[:len(b)-1]).Int64())
    }
    return int(big.NewInt(0).SetBytes(b[:len(b)-1]).Int64())
}

https://play.golang.org/p/mR5Sp5hu4jk

或新的(https://play.golang.org/p/7ZAK4QL96FO

(该包还提供了填充现有切片的功能)

https://golang.org/pkg/math/big/#Int.FillBytes


1
投票

添加此选项来处理基本的 uint8 到 byte[] 转换

foo := 255 // 1 - 255
ufoo := uint16(foo) 
far := []byte{0,0}
binary.LittleEndian.PutUint16(far, ufoo)
bar := int(far[0]) // back to int
fmt.Println("foo, far, bar : ",foo,far,bar)

输出:

foo, far, bar :  255 [255 0] 255


1
投票

这是另一个选项,基于 Go 源代码 [1]:

package main

import (
   "encoding/binary"
   "fmt"
   "math/bits"
)

func encodeUint(x uint64) []byte {
   buf := make([]byte, 8)
   binary.BigEndian.PutUint64(buf, x)
   return buf[bits.LeadingZeros64(x) >> 3:]
}

func main() {
   for x := 0; x <= 64; x += 8 {
      buf := encodeUint(1<<x-1)
      fmt.Println(buf)
   }
}

结果:

[]
[255]
[255 255]
[255 255 255]
[255 255 255 255]
[255 255 255 255 255]
[255 255 255 255 255 255]
[255 255 255 255 255 255 255]
[255 255 255 255 255 255 255 255]

math/big
快得多:

BenchmarkBig-12         28348621                40.62 ns/op
BenchmarkBit-12         731601145                1.641 ns/op
  1. https://github.com/golang/go/blob/go1.16.5/src/encoding/gob/encode.go#L113-L117

0
投票

将整数转换为字节切片。

import (
    "bytes"
    "encoding/binary"
    "log"
)

func IntToBytes(num int64) []byte {
    buff := new(bytes.Buffer)
    bigOrLittleEndian := binary.BigEndian
    err := binary.Write(buff, bigOrLittleEndian, num)
    if err != nil {
        log.Panic(err)
    }

    return buff.Bytes()
}

0
投票

也许简单的方法是使用 protobuf,请参阅 Protocol Buffer Basics: Go

定义消息如

message MyData {
  int32 id = 1;
}

了解更多信息定义协议格式

// Write
out, err := proto.Marshal(mydata)

阅读更多内容写消息


0
投票

尝试使用 math/big 包将 bytes 数组转换为 int 并将 int 转换为 bytes 数组。

package main

import (
    "fmt"
    "math/big"
)

func main() {
    // Convert int to []byte
    var int_to_encode int64 = 65535
    var bytes_array []byte = big.NewInt(int_to_encode).Bytes()
    fmt.Println("bytes array", bytes_array)

    // Convert []byte to int
    var decoded_int int64 = new(big.Int).SetBytes(bytes_array).Int64()
    fmt.Println("decoded int", decoded_int)
}



0
投票

这是最直接的(也是最短的(也是最安全的)(也许是最高效的))方式:

buf.Bytes()
是字节切片类型。

    var val uint32 = 42
    buf := new(bytes.Buffer)
    err := binary.Write(buf, binary.LittleEndian, val)
    if err != nil {
        fmt.Println("binary.Write failed:", err)
    }
    fmt.Printf("% x\n", buf.Bytes())

另请参阅https://stackoverflow.com/a/74819602/589493


0
投票

步骤1.忽略字节序,对任意类型直接执行:

func toBytes[T any](val T) []byte {
    return unsafe.Slice((*byte)(unsafe.Pointer(&val)), unsafe.Sizeof(val))
}

(还可以考虑在类型 T 上添加 整数约束

第 2 步:您真的需要不同字节序机器之间的可移植性吗?好的,这是一个想法:

func toLEBytes[T any](val T) []byte {
    bytes := toBytes(val)
    if runninOnBigEndian() {
        slices.Reverse(bytes)
    }
    return bytes
}

您唯一需要的就是实施

runninOnBigEndian()
。首先阅读这个问题的答案: 在 Go 中检查字节序的更好方法


-6
投票

转换为字符串有什么问题吗?

[]byte(fmt.Sprintf("%d", myint))
© www.soinside.com 2019 - 2024. All rights reserved.