Passing arrays as function arguments - go

I expected the following code snippet either to produce a as {0x01, 0x02} (pass by value) or as {0x03, 0x02, 0x01} (pass by reference). Strangely, it produces the output as {0x03, 0x02}. Could you please help me understand why is that?
package main
import "fmt"
func test1(t []byte) {
t[0] = 0x03
t = append(t, 0x01 )
}
func main() {
a := []byte{0x01, 0x02 }
test1(a)
_ = a
fmt.Printf("%v", a)
}

In Go []byte is not an array, it's a byte slice.
What happened is that the size of a was 2, and because of that, after its first element was changed to 3, append allocated a new bigger slice - and t was set to the address of the new slice that was allocated, but that doesn't affect the a in main.
From A Tour of Go about append:
If the backing array of s is too small to fit all the given values a bigger array will be allocated. The returned slice will point to the newly allocated array.

The slice header is passed by value, but it references the same backing array. So when you change the first value it is changed in the original array as well. When you call append a new slice header is generated and written to the space occupied by the original argument value thus staying local to the method.

Related

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)

Convert `byte` array to `uint32` array

I'd like to use byte array as uint32 array, then get the first element of the uint32 array. But I can not get the following code to work. Could anybody let me know how to cast a byte array to a unit32 array? Thanks.
// vim: set noexpandtab tabstop=2:
package main
import (
"unsafe"
"fmt"
)
func main() {
x := []byte{'\x01', '\x02', '\x03', '\x04', '\x06', '\x07', '\x08', '\x09'}
fmt.Printf("%#v\n", x)
fmt.Printf("%#v\n", []int32(unsafe.Pointer(x))[0])
}
It would be
fmt.Printf("%#v\n", (*(*[]int32)(unsafe.Pointer(&x)))[0])
but one should remember that it still would have len = cap = 8 (*), and carefully check for boundaries themselves.
The expression clarification
unsafe.Pointer(&x) // an uintptr to an `x` slice
(*[]int32)(...) // a type conversion
// it's the same syntax when you do float64(42)
// but in this case you need extra parentheses around the
// type name to make it unambiguous for the parser
// so, it converts a unitptr to a pointer to a int32 slice
*(...) // here it's just a pointer dereference. So you obtain a slice
// from a pointer to a slice, to index it after
(*) cap is not guaranteed to be 8 in this particular case (but it does not really matter).

Reassigning a slice parameter acts differently

package main
import "fmt"
func main() {
paths := []string{"hello", "world", "mars"}
var result = delete(paths, 1)
fmt.Println(result)
fmt.Println(paths)
}
func delete(paths []string, index int) []string {
paths = append(paths[:index], paths[index+1:]...)
return paths
}
The result of the code above is the following:
[hello mars]
[hello mars mars]
As you see, the second fmt.Println(paths) obviously uses the modified slice but does not use the reassigned value. Why is that? I was expecting it to print [hello mars] like in the print before.
I know that paths being passed is not the same slice as paths parameter in the delete() function expect for referencing the same underlying array. But I still don't understand how I changed the underlying array of the paths being passed to delete function as it prints [hello mars mars] instead of [hello world mars].
Because, as you said, the same underlying array is in use. When you do the append, paths[:1] is a slice of length 1 and capacity 3, and paths[2:] is a slice of length 1, so there is enough room in the underlying array of the first slice to append the new value without allocating a new array. paths in main is still a slice of length 3 since it was never modified, but since the underlying array was modified (specifically element 1), you see the value that you see.
You may want to take a look at https://blog.golang.org/go-slices-usage-and-internals if you haven't already.

Why a slice []struct doesn't behave same as []builtin?

The slices are references to the underlying array. This makes sense and seems to work on builtin/primitive types but why is not working on structs? I assume that even if I update a struct field the reference/address is still the same.
package main
import "fmt"
type My struct {
Name string
}
func main() {
x := []int{1}
update2(x)
fmt.Println(x[0])
update(x)
fmt.Println(x[0])
my := My{Name: ""}
update3([]My{my})
// Why my[0].Name is not "many" ?
fmt.Println(my)
}
func update(x []int) {
x[0] = 999
return
}
func update2(x []int) {
x[0] = 1000
return
}
func update3(x []My) {
x[0].Name = "many"
return
}
To clarify: I'm aware that I could use pointers for both cases. I'm only intrigued why the struct is not updated (unlike the int).
What you do when calling update3 is you pass a new array, containing copies of the value, and you immediately discard the array. This is different from what you do with the primitive, as you keep the array.
There are two approaches here.
1) use an array of pointers instead of an array of values:
You could define update3 like this:
func update3(x []*My) {
x[0].Name = "many"
return
}
and call it using
update3([]*My{&my})
2) write in the array (in the same way you deal with the primitive)
arr := make([]My,1)
arr[0] = My{Name: ""}
update3(arr)
From the GO FAQ:
As in all languages in the C family, everything in Go is passed by
value. That is, a function always gets a copy of the thing being
passed, as if there were an assignment statement assigning the value
to the parameter. For instance, passing an int value to a function
makes a copy of the int, and passing a pointer value makes a copy of
the pointer, but not the data it points to. (See the next section for
a discussion of how this affects method receivers.)
Map and slice values behave like pointers: they are descriptors that
contain pointers to the underlying map or slice data. Copying a map or
slice value doesn't copy the data it points to.
Thus when you pass my you are passing a copy of your struct and the calling code won't see any changes made to that copy.
To have the function change the data in teh struct you have to pass a pointer to the struct.
Your third test is not the same as the first two. Look at this (Playground). In this case, you do not need to use pointers as you are not modifying the slice itself. You are modifying an element of the underlying array. If you wanted to modify the slice, by for instance, appending a new element, you would need to use a pointer to pass the slice by reference. Notice that I changed the prints to display the type as well as the value.

Why struct buffer do not need to initialize

I am trying to use Buffer package and copy the following code from Buffer documentation.
package main
import (
"bytes"
"fmt"
"os"
)
func main() {
var b bytes.Buffer // A Buffer needs no initialization.
b.Write([]byte("Hello "))
fmt.Fprintf(&b, "world!")
b.WriteTo(os.Stdout)
}
Why do Buffer here, not to be initialize?
As you can see here Buffer consists just of some ints, the buf slice and some arrays. All of them need no initialization, since go has zero values.
You can read more about slices and arrays and how they work here.
It is initialized. When you do not specifically initialize a variable, go will initialize it to its zero value. That means all the internal fields of a bytes.Buffer gets the value 0, or similar for the relevant types (e.g. nil for pointers).
The authors then implemented bytes.Buffer so all values being 0 is a meaningful starting point(It means an empty buffer), so programmers doesn't need to explicitly initialize it in order to start using a Buffer.
This due to the fact that when you call the Fprintf method, the bytes.Buffer.Write method is implicitely called, and as per the doc:
Write appends the contents of p to the buffer, growing the buffer as needed.
If you look at the source code, Write calls the grow function: func (b *Buffer) grow(n int) int.
This function recognizes that the buffer is empty, because it assumes that an empty buffer has 0 values for its internal fields, which is actually how a bytes.Buffer structure is initialized by default, just like every structure in go.

Resources