parenthesis and curly braces difference in golang - go

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

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

golang, £ char causing weird  character

I have a function that generates a random string from a string of valid characters. I'm occasionally getting weird results when it selects a £
I've reproduced it to the following minimal example:
func foo() string {
validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*"
var result strings.Builder
for i := 0; i < len(validChars); i++ {
currChar := validChars[i]
result.WriteString(string(currChar))
}
return result.String()
}
I would expect this to return
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*
But it doesn't, it produces
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!£$%^&*
^
where did you come from ?
if I take the £ sign out of the original validChars string, that weird A goes away.
func foo() string {
validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!$%^&*"
var result strings.Builder
for i := 0; i < len(validChars); i++ {
currChar := validChars[i]
result.WriteString(string(currChar))
}
return result.String()
}
This produces
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~#:!$%^&*
A string is a type alias for []byte. Your mental model of a string is probably that it consists of a slice of characters - or, as we call it in Go: a slice of rune.
For many runes in your validChars string this is fine, as they are part of the ASCII chars and can therefore be represented in a single byte in UTF-8. However, the £ rune is represented as 2 bytes.
Now if we consider a string £, it consists of 1 rune but 2 bytes. As I've mentioned, a string is really just a []byte. If we grab the first element like you are effectively doing in your sample, we will only get the first of the two bytes that represent £. When you convert it back to a string, it gives you an unexpected rune.
The fix for your problem is to first convert string validChars to a []rune. Then, you can access its individual runes (rather than bytes) by index, and foo will work as expected. You can see it in action in this playground.
Also note that len(validChars) will give you the count of bytes in the string. To get the count of runes, use utf8.RuneCountInString instead.
Finally, here's a blog post from Rob Pike on the subject that you may find interesting.

Go Reflect Array

The structure is like:
type Auth_msg struct {
Msg_class [2]byte
Msg_content_pty [2]byte
I am fresh to use Reflect in Go and I encounter this:
panic: reflect: call of reflect.Value.Bytes on array Value
This occurs when I run val.Field(i).Bytes(), however the when I try to print it: fmt.PrintLn(val.Field(i)), it prints out the right arrays.
I just wonder, how I can retrieve the Msg_class in an array or a slice?
In Go, there is a distinction between an array and a slice. Value.Bytes() explicitly works only for a byte slice (link to docs).
note : I don't know why it doesn't handle byte arrays ; it probably was written that way, and it makes the implementation of reflect.Bytes() simpler. Anyway : slices are definitely the common use case in Go, and it is easy to convert an array to a slice :
You can create a slice pointing to the array using [:] :
v := reflect.ValueOf(msg.Msg_class)
fmt.Println("kind :", v.Kind()) // prints 'array'
// fmt.Printf("bytes : % x\n", v.Bytes()) // panics
v = reflect.ValueOf(msg.Msg_class[:])
fmt.Println("kind :", v.Kind()) // prints 'slice'
fmt.Printf("bytes : % x\n", v.Bytes()) // works
https://play.golang.org/p/sKcGaru4rOq
To turn an array into a slice using reflect, you can call .Slice() on a reflect.Value.
One constraint, mentioned in the doc, is that the array value must be addressable.
I haven't got all the details sorted out, but one way to make sure the reflect Value is addressable is to call reflect.ValueOf() on a pointer, and then call .Elem() on that pointer value :
var arr [2]byte
arr[0] = 'g'
arr[1] = 'o'
// take ValueOf a *pointer* to your array, and let reflect dereference it :
v := reflect.ValueOf(&arr).Elem()
// this sets the "canAddr" flag on this value
fmt.Println("arr value - CanAddr() :", v.CanAddr()) // prints 'true'
slice := v.Slice(0, v.Len())
fmt.Printf("arr bytes : % x\n", slice.Bytes()) // prints '67 6f'
// for a field inside a struct : take a pointer to the struct
var msg Auth_msg
msg.Msg_class[0] = 'a'
msg.Msg_class[1] = 'z'
v = reflect.ValueOf(&msg).Elem()
fmt.Println("msg value - CanAddr() :", v.CanAddr()) // prints 'true'
// now reflect accepts to call ".Slice()" on one of its fields :
field := v.FieldByName("Msg_class")
slice = field.Slice(0, field.Len())
fmt.Printf("msg.Msg_class bytes : % x\n", slice.Bytes()) // prints '61 7a'
https://play.golang.org/p/SqM7yxl2D96

Why with a Go interface{} as a parameter, when I call func with string, will it cast one alloc/ns?

I have a Go function that has interface{} as a parameter. When I call the function with string, it will cast one alloc/ns. Why?
func foo(...interface{}) error {
....
}
func use() {
var str = "use it"
e := foo(str)
_ = e
}
Internally, an interface variable is a two word structure. The first word is a pointer to the information about the dynamic type of the variable. The second word will either (a) contain the variable's dynamic value if it will fit in a word, or (b) contain a pointer to memory holding the dynamic value if it is larger.
A string variable is larger than a word, since it holds both it's length and a pointer to the underlying character data. So storing a string in a an interface variable involves allocating some memory to hold that value.

What is the difference between [0] and [:1] in Go?

I split a string by spaces:
splstr = strings.Split(str, " ")
Then I iterate each word, and look at the first character like this:
splstr[i][0] == "#"
But I got these errors from that line:
... : cannot convert "#" to type uint8
... : invalid operation: splstr[i][0] == "#" (mismatched types uint8 and string)
But then I spliced it:
splstr[i][:1] == "#"
And that works. I get why [:1] is of type string, but why is [0] of type uint8? (I'm using Go 1.1.)
Because the array notation on a string gives access to the string's bytes, as documented in the language spec:
http://golang.org/ref/spec#String_types
A string's bytes can be accessed by integer indices 0 through len(s)-1.
(byte is an alias for uint8)
[x:x] ([:x] is a form of [0:x]) will cut a slice into another slice while [x] will retrieve the object at index x. The difference is shown below:
arr := "#####"
fmt.Println(arr[:1]) // will print out a string
fmt.Println(arr[0]) // will print out a byte
If the string is converted into []byte:
arr := []byte("#####")
fmt.Println(arr[:1]) // will print out a slice of bytes
fmt.Println(arr[0]) // will print out a byte
You can try this yourself at http://play.golang.org/p/OOZQqXTaYK

Resources