Putting int8 into byte array - go

I have the following byte array:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = value // cannot use type int8 as type []byte in assignment
And when I want to put a char value into the byte array I get the error that I cannot use type int8 as type []byte in assignment. What's wrong? How do I do this?

The issue you're having their is that although int8 and byte are roughly equivalent, they're not the same type. Go is a little stricter about this than, say, PHP (which isn't strict about much). You can get around this by explicitly casting the value to byte:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = byte(value) // cast int8 to byte

Try this:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = byte(value)
UPDATE: Took out the code converting negative numbers to positive ones. It appears that byte(...) already does this conversion in current versions of Go.

Related

Use string constant as byte value in array or slice literal

I am trying to make a global byte array from a string with:
point := []byte{0x23f32...}
But I am getting the error:
untyped string constant "0x23f32...) as byte value in array or slice literal
I know what I should use a type conversion to convert a string to a slice of bytes, i.e. use of () instead of {}.
point := []byte(0x23f32...)
The code in the question is a composite literal. However, I am using operators as a global variable, so I think that I cannot declare the variable that way. Also, further in the code, logically, I will also have to use [33]byte, so I'm worried about how to declare point []byte here so that I don't have a type error later like "mismatched types [32]byte and []byte".
So keeping these two questions in mind, could you please tell me how to deal with point := []byte here correctly?
0x23f32... is a integer literal and won't convert to a byte (or bytes). You will get this compile-time error for var point = []byte{0x23f32}
cannot use 0x23f32 (untyped int constant 147250) as byte value in array or slice literal (overflows)
Assuming that what you expect to get (it's not clear from your question) from something like
point := []byte{0x23f32 . . . }
is essentially
point := []byte{0x23,0xf3,0x2? . . . }
...
First, if you are trying to declare a "global" variable (e.g. a package-scoped variable), you need to use the var <name> <type> = <value> form. You can't use <name> := <value>.
Second, you can initialize a []byte in a couple different ways:
var p1 []byte = []byte{ 0x12, 0x23, 0x45, . . . }
an array/slice of hex constants, each needs to be in the range 0x00-0xFF (0-255 decimal).
var p2 []byte = []byte{ "\x12\x23\x45 . . ." }
a string containing the desired bytes.
var p3 []byte = []byte{ 18, 35, 69 . . . }
an array/slice of decimal constants
var p4 []byte = []byte{ '\x12', '\x23', '\x45' . . . }
an array slice of individual byte literals. Note that if one specifies a value outside the range of a byte (0x00–0xFF, 0-255 decimal), you'll get a compile time error along the lines of:
cannot use 'ш' (untyped rune constant 1096) as byte value in array or slice literal (overflows)
Note that the above 4 examples all yield exactly the same value.
If you need to convert 32 bit number to bytes, you can do this:
package main
import (
"encoding/binary"
"fmt"
)
func main() {
var point [4]byte
binary.BigEndian.PutUint32(point[:], 0x23f32)
fmt.Println(point) // [0 2 63 50]
}
https://godocs.io/encoding/binary#ByteOrder.PutUint32

Cannot convert byte to int in Golang

This is strange but I cannot convert byte value into int.
Here is the code:
fmt.Println("numMsgsByte is:", numMsgsByte)
numMsgsStr := string(numMsgsByte)
fmt.Println("numMsgsStr is:", numMsgsStr)
numMsgs, err = strconv.Atoi(numMsgsStr)
if err != nil {
log.Println("error in msg conversion", err)
return 0
}
The terminal print out:
numMsgsByte is: [5]
numMsgsStr is:
counter.go:51: error in msg conversion strconv.Atoi: parsing "\x05": invalid syntax
What could be wrong here? How can I fix it?
numMsgByte is not a byte, it is a []byte, which contains 5 (not "5"). When you convert it to string using string(numMsgByte), you get a string "\x5".
What you need is: int(numMsgType[0])
The correct way to get an integer out of Redis using redigo would be to just use redis.Int in the first place, instead of using redis.Bytes and trying to convert the result to an int yourself.
In general though, to convert an arbitrary byte array to the integer it represents, you would use the encoding/binary package. You'll need to know some key details about the byte array though:
Does it represent a signed or unsigned value?
Of what width? 32 bit? 64 bit?
Of what byte order? Big-endian? Little-endian?
Are you sure it's represented as an integer, not e.g. a float, or a string representation of a number?
To quote the example from the docs:
b := []byte{0xe8, 0x03, 0xd0, 0x07}
x1 := binary.LittleEndian.Uint16(b[0:])
x2 := binary.LittleEndian.Uint16(b[2:])
fmt.Printf("%#04x %#04x\n", x1, x2)

How to convert uint8 slice to string

What's the best way to convert from []uint8 to string?
I'm using http://github.com/confluentinc/confluent-kafka-go/kafka
To read events from kafka. But it does not return plain string event.
It returns event with type []uint8.
How can I convert this event from []uint8 to string?
byte is an alias for uint8, which means that a slice of uint8) (aka []uint8) is also a slice of byte (aka []byte).
And byte slices and strings are directly convertible, due to the fact that strings are backed by byte slices:
myByteSlice := []byte{ ... } // same as myByteSlice := []uint8{ ... }
myString := string(myByteSlice) // myString is a string representation of the byte slice
myOtherSlice := []byte(myString) // Converted back to byte slice

Type conversion from byte slice to struct with unsafe

I'm trying to understand why my code in Go doesn't work the way I thought it would. When I execute this test, it fails:
func TestConversion(t *testing.T) {
type myType struct {
a uint8
value uint64
}
myVar1 := myType{a: 1, value: 12345}
var copyFrom []byte
copyFromHeader := (*reflect.SliceHeader)(unsafe.Pointer(&copyFrom))
copyFromHeader.Data = uintptr(unsafe.Pointer(&myVar1))
copyFromHeader.Cap = 9
copyFromHeader.Len = 9
copyTo := make([]byte, len(copyFrom))
for i := range copyFrom {
copyTo[i] = copyFrom[i]
}
myVar2 := (*myType)(unsafe.Pointer(&copyFrom[0]))
myVar3 := (*myType)(unsafe.Pointer(&copyTo[0]))
if myVar2.value != myVar3.value {
t.Fatalf("Expected myVar3.value to be %d, but it is %d", myVar2.value, myVar3.value)
}
}
The output will be:
slab_test.go:67: Expected myVar3.value to be 12345, but it is 57
However, if I increase copyFromHeader.Data by 1 before the copying of the data, then it all works fine. Like this:
copyFromHeader.Data = uintptr(unsafe.Pointer(&myVar1)) + 1
I don't understand why it seems to shift the underlying data by one byte.
There are 7 padding bytes between a and value. You're only getting the least significant byte of 12345 (57) in value. When you move copyFrom down by one byte, the values of myVar2.value and myVar3.value are both 48 (the second byte of 12345), so your test passes. It should work if you change 9 to 16.
Is there some particular reason you're copying the struct that way?

Implicit type conversion between uint8 and byte

As said in The Go Programming Language on page 55: "an EXPLICIT conversion is required to convert a value from one type to another", even if both of them have same underlying type. For example:
type myByte byte
func main() {
var a byte
var b myByte
a = b // Compile error: cannot use b (type myByte) as type byte in assignment
a = byte(b) // OK
}
But for uint8 and byte, I'm surprised that the conversion is implicit:
func main() {
var a byte
var b uint8
a = b // OK
b = a // OK
}
So why?
byte is an alias for uint8 and is equivalent to uint8 in all ways.
From GoDoc:
type Byte
byte is an alias for uint8 and is equivalent to uint8 in all ways. It is used, by convention, to distinguish byte values from 8-bit unsigned integer values.
type byte byte // Really: type byte = uint8 (see golang.org/issue/21601)
https://golang.org/pkg/builtin/#byte
Earlier, on page 52 of The Go Programming Language, "the type byte is a synonym for uint8".
The Go Programming Language Specification
Numeric types
uint8 the set of all unsigned 8-bit integers (0 to 255)
byte alias for uint8

Resources