Use string constant as byte value in array or slice literal - go

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

Related

Does the conversion from string to rune slice make a copy?

I'm teaching myself Go from a C background.
The code below works as I expect (the first two Printf() will access bytes, the last two Printf() will access codepoints).
What I am not clear is if this involves any copying of data.
package main
import "fmt"
var a string
func main() {
a = "èe"
fmt.Printf("%d\n", a[0])
fmt.Printf("%d\n", a[1])
fmt.Println("")
fmt.Printf("%d\n", []rune(a)[0])
fmt.Printf("%d\n", []rune(a)[1])
}
In other words:
does []rune("string") create an array of runes and fill it with the runes corresponding to "string", or it's just the compiler that figures out how to get runes from the string bytes?
It is not possible to turn []uint8 (i.e. a string) into []int32 (an alias for []rune) without allocating an array.
Also, strings are immutable in Go but slices are not, so the conversion to both []byte and []rune must copy the string's bytes in some way or another.
It involves a copy because:
strings are immutable; if the conversion []rune(s) didn't make a copy, you would be able to index the rune slice and change the string contents
a string value is a "(possibly empty) sequence of bytes", where byte is an alias of uint8, whereas a rune is a "an integer value identifying a Unicode code point" and an alias of int32. The types are not identical and even the lengths may not be the same:
a = "èe"
r := []rune(a)
fmt.Println(len(a)) // 3 (3 bytes)
fmt.Println(len(r)) // 2 (2 Unicode code points)

CGO: how to free the go slice which is backed by a C Array [duplicate]

In the Golang wiki, under "Turning C arrays into Go slices", there is a block of code that demonstrates how to create a Go slice backed by a C array.
import "C"
import "unsafe"
...
var theCArray *C.YourType = C.getTheArray()
length := C.getTheArrayLength()
slice := (*[1 << 30]C.YourType)(unsafe.Pointer(theCArray))[:length:length]
Can anyone explain exactly what (*[1 << 30]C.YourType) does? How does it turn an unsafe.Pointer into a Go slice?
*[1 << 30]C.YourType doesn't do anything itself, it's a type. Specifically, it's a pointer to an array of size 1 << 30, of C.YourType values. The size is arbitrary, and only represents an upper bound that needs to be valid on the host system.
What you're doing in the third expression is a type conversion.
This converts the unsafe.Pointer to a *[1 << 30]C.YourType.
Then, you're taking that converted array value, and turning it into a slice with a full slice expression (Array values don't need to be dereferenced for a slice expression, so there is no need to prefix the value with a *, even though it is a pointer).
You could expand this out a bit like so:
// unsafe.Pointer to the C array
unsafePtr := unsafe.Pointer(theCArray)
// convert unsafePtr to a pointer of the type *[1 << 30]C.YourType
arrayPtr := (*[1 << 30]C.YourType)(unsafePtr)
// slice the array into a Go slice, with the same backing array
// as theCArray, making sure to specify the capacity as well as
// the length.
slice := arrayPtr[:length:length]
This construct has been replaced by a generalized unsafe.Slice function in go1.17:
slice := unsafe.Slice(theCArray, length)

parenthesis and curly braces difference in golang

a := []byte("H") //works
a := []byte{"H"} //does not compile
What is the conceptual difference between () and {} as used above?
The reason is the difference between type conversions and slice literals.
_ = []byte("Hi!") // Converts a string literal to a []byte.
_ = []byte{'H', 'i', '!'} // Initializes a []byte literal
Your second example []byte{"H"} fails to compile because "H" is a string literal that is being used in place of a rune literal, it's comparable to trying to assign a string to a byte typed variable:
var y byte = 'H' // OK
var x byte = "H" // ERROR: cannot use "H" (type string) as type byte in assignment
In the first one a := []byte("H") you are type casting the string "H" into a byte array.
In the second one a := []byte{"H"} you are defining a byte array and assigning "H" as it's first value, which is invalid.
You can compare the second one with defining a string array:
s := []string{"hello","world",".."} // works
f := []string{1,2,4} // fails because the datatype is wrong

golang how does the rune() function work

I came across a function posted online that used the rune() function in golang, but I am having a hard time looking up what it is. I am going through the tutorial and inexperienced with the docs so it is hard to find what I am looking for.
Specifically, I am trying to see why this fails...
fmt.Println(rune("foo"))
and this does not
fmt.Println([]rune("foo"))
rune is a type in Go. It's just an alias for int32, but it's usually used to represent Unicode points. rune() isn't a function, it's syntax for type conversion into rune. Conversions in Go always have the syntax type() which might make them look like functions.
The first bit of code fails because conversion of strings to numeric types isn't defined in Go. However conversion of strings to slices of runes/int32s is defined like this in language specification:
Converting a value of a string type to a slice of runes type yields a
slice containing the individual Unicode code points of the string.
[golang.org]
So your example prints a slice of runes with values 102, 111 and 111
As stated in #Michael's first-rate comment fmt.Println([]rune("foo")) is a conversion of a string to a slice of runes []rune. When you convert from string to []rune, each utf-8 char in that string becomes a Rune. See https://stackoverflow.com/a/51611567/12817546. Similarly, in the reverse conversion, when converted from []rune to string, each rune becomes a utf-8 char in the string. See https://stackoverflow.com/a/51611567/12817546. A []rune can also be set to a byte, float64, int or a bool.
package main
import (
. "fmt"
)
func main() {
r := []rune("foo")
c := []interface{}{byte(r[0]), float64(r[0]), int(r[0]), r, string(r), r[0] != 0}
checkType(c)
}
func checkType(s []interface{}) {
for k, _ := range s {
Printf("%T %v\n", s[k], s[k])
}
}
byte(r[0]) is set to “uint8 102”, float64(r[0]) is set to “float64 102”,int(r[0]) is set to “int 102”, r is the rune” []int32 [102 111 111]”, string(r) prints “string foo”, r[0] != 0 and shows “bool true”.
[]rune to string conversion is supported natively by the spec. See the comment in https://stackoverflow.com/a/46021588/12817546. In Go then a string is a sequence of bytes. However, since multiple bytes can represent a rune code-point, a string value can also contain runes. So, it can be converted to a []rune , or vice versa. See https://stackoverflow.com/a/19325804/12817546.
Note, there are only two built-in type aliases in Go, byte (alias of uint8) and rune (alias of int32). See https://Go101.org/article/type-system-overview.html. Rune literals are just 32-bit integer values. For example, the rune literal 'a' is actually the number "97". See https://stackoverflow.com/a/19311218/12817546. Quotes edited.

Putting int8 into byte array

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.

Resources