How to determine if the pointer passed as a function argument is being modified or a copy is being modified? - go

package main
import (
"fmt"
)
type Numbers struct {
x int
y int
}
func initial(number *Numbers) {
number.x = 1
number.y = 1
}
func final(number *Numbers) {
number = &Numbers{2, 2}
}
func main() {
p := Numbers{0, 0}
fmt.Println(p) //Prints {0 0}
initial(&p)
fmt.Println(p) //Prints {1 1}
final(&p)
fmt.Println(p) //Expected to print {2, 2} but prints {1, 1}
}
Why does the initial function modify the pointer, while the final function modifies a copy of the pointer?
Both initial and final's function parameters point to the memory address of p in main; initial manages to change p, while final can't.
Any explanation so as why this is the case would be greatly appreciated.

To modify the data pointed to by a pointer, you must dereference the pointer. The dereference operator is *. However, Go will implicitly insert the dereference operation in some cases for ease of use. For example, number.x = 1 is translated to (*number).x = 1.
This implicit translation may be confusing, but you should see that if it that translation didn't happen, then the expression number.x = 1 would be meaningless, since number is a pointer type and pointers don't have fields.
So in summary, the initial function has implicit pointer dereference, while final does not.
If you changed final to explicitly and correctly dereference, *number = Numbers{2, 2}, then it will also change p.

The initial function works on the passed pointer, which is pointing to the variable allocated in main. All changes are performed on the object allocated in main.
The final function receives the same pointer as an argument, however, it assigns the pointer to another Numbers instance. The object in main never changes.
There is no copying involved in either function.

Related

Mutate a slice passed as an argument to a function in Go

I wrote some code where a function f takes a slice s as an argument and modifies it without returning it.
Since slices can be considered as references to underlying arrays, I thought that the slice would be actually modified outside of that function's scope, but it's not the case.
An example would be the code below (https://play.golang.org/p/Y5JUmDtRXrz).
package main
import (
"fmt"
)
func pop(s []int) int {
first, s := s[0], s[1:]
return first
}
func main() {
s := []int{0, 1, 2, 3}
first := pop(s)
fmt.Println(first, s)
}
pop(s) actually returns 0, which is expected. But then in the output s still has 0 as its first element.
0 [0 1 2 3]
Program exited.
Why? And how could I solve this ?
Two separate things are happening here, both of which prevent this from behaving as you expect:
func pop(s []int) int {
first, s := s[0], s[1:]
The first (and simpler) issue is you're defining a new local variable s here, which shadows you function parameter s.
Second, slices do point to an underlying array, but the slice is still passed by copy, just like everything else. That means that:
s = s[1:]
Modifies your copy of s to have a different window on the underlying array. That doesn't change the slice in the caller. However, if you change the values in the underlying array, that will be reflected in the caller, e.g.:
s[1] = 42
You can learn more about this throughout the Tour and on the Go blog.
The line first, s := s[0], s[1:] creates a new variable s since you are using :=. On top of that if you want to modify the slice you need to pass it by pointer.
Passing it by value, it will refer to the same underlying array, but the slice itself is a copy. So changes to the underlying array would be reflected in main, but changes to the slice itself would not.
Here is an example of passing the slice by pointer.
package main
import (
"fmt"
)
func pop(s *[]int) int {
first := (*s)[0]
*s = (*s)[1:]
return first
}
func main() {
s := []int{0, 1, 2, 3}
first := pop(&s)
fmt.Println(first, s)
}

Any one can make sense of connStateInterface?

func (c *conn) setState(nc net.Conn, state ConnState) {
...
c.curState.Store(connStateInterface[state])
...
}
// connStateInterface is an array of the interface{} versions of
// ConnState values, so we can use them in atomic.Values later without
// paying the cost of shoving their integers in an interface{}.
var connStateInterface = [...]interface{}{
StateNew: StateNew,
StateActive: StateActive,
StateIdle: StateIdle,
StateHijacked: StateHijacked,
StateClosed: StateClosed,
}
I can't figure out the trick with connStateInterface, how exactly does it work?
There's a few things going on here...
The [...] declaration creates an actual array instead of a slice, so that indirection is removed. What's being declared here is an array of interface{} types... so you might wonder why the weird map-looking notation?
The StateXXX variables are simply constants declared further above, so they are ints... so the declaration is actually of the form index: value.
Here's a less obfuscated example of that using an array of ints:
var i = [...]int{4: 2, 2: 7}
This will allocate an array containing:
[0, 0, 7, 0, 2]
... note that index 2 has 7, index 4 has 2. Not a common way of declaring an array, but it's valid Go.
So going back to the original declaration, just take the example I gave above, and instead of int, make the array of type interface{}:
var i = [...]interface{}{4: 2, 2: 7}
And you'll get a similar array, but with nil interface values in place of zeroes.
Getting even closer to the original code, the StateXXX constants are just ints, only not literals like in my example.
So, what's the point of all this? Why all the obfuscation?
It's a performance hack. The function c.curState.Store() takes an argument of type interface{}. If you were to pass it an int, the compiled code would have to fumble about with converting the type on each call. A more clear (though obviously impractical) illustration of this might be:
var val interface{}
for i := 0; i < 1000000; i++ {
// the types are different, compiler has to fumble int vs. interface{}
val = i
// do something with val
}
Every time you do val = i a conversion between int and interface{} needs to happen. The code you posted avoids this by creating a static lookup table where all the values are already of type interface.
Therefore, this:
c.curState.Store(connStateInterface[state])
is more efficient than this:
c.curState.Store(state)
Since state would, in this case, need to undergo the int -> interface{} conversion. In the optimized code, state is merely an index looking up a value into an array, the result of which gets you an interface{}... so the int -> interface{} type conversion is avoided.
I'm not familiar with that code, but I'd imagine it's in a critical path and the nanoseconds or whatever savings shaved off likely makes a difference.

Reassigning in pointer method receiver

What I understand about pointer method receiver and non-pointer method receiver is first one can be modified in the method and next one isn't.
So, following worked exactly as I expected.
type student struct {
name string
age int
}
func (s *student) update() {
s.name = "unknown"
s.age = 0
}
func main() {
s := student{"hongseok", 13}
fmt.Println(s)
s.update()
fmt.Println(s)
}
It prints hongseok/13 and unknown/0.
But, I want to replace whole s in update method at once with reassigning. So, I've just altered update method as bellow.
func (s *student) update() {
s = &student{"unknown", 0}
}
And it doesn't change s in main method and prints double hongseok/13.
func (s *student) update() {
*s = student{"unknown", 0}
}
Above change fix the problem.
I think there's no semantic difference. What am I missing?
In the first example:
func (s *student) update() {
s = &student{"unknown", 0}
}
You are assigning an entirely new "pointer value" to s, and the new *s points at a new student value. The variable s is scoped only to the method body, so there are no side effects after this returns.
In the second example
func (s *student) update() {
*s = student{"unknown", 0}
}
You are dereferencing s, and changing the value of *s to point to a new student value, or to put it differently, you are putting a new student value at the address where s points.
In this example you're changing the address that is stored in s to a different value;
func (s *student) update() {
s = &student{"unknown", 0}
}
While using a pointer is regarded as 'passing by reference' the reference itself is a value like any other that is pushed onto the call stack. When you return to main, the value of s is whatever it was in that scope. So to give something more concrete, you called main with s = 1 (calling the addresses 1 and 2 for simplicity), in the method you allocate a new student located at address 2 and you set s = 2, when you return that version of s is popped from the stack and the s in main points to 1 which is unchanged.
In this latter example;
func (s *student) update() {
*s = student{"unknown", 0}
}
You're dereferencing s and assigning a new object to that location, overwriting the existing memory. When you return the pointer in main is still pointing to the same location but you have different data at that location in memory. So in this example you're writing a new student instance to address 1 so when you return you see the new value in the calling scope.
I think, your main problem is that you don't understand well neither one of two concepts that appear in your question.
Let start with pointers. When you don't use pointers, assigning of value means create a simple copy of previous value. The new value is not bound any way with previous one. That means if you change the old value or new, it does not influence the second one. This is normal for primitive types (like ints, bool, string) and structures.
a := 1
b := a
a++ // a was changed, but value of b does not change at all
And now the pointers - it is something that points to some space into memory. For simplicity we create two pointers and both will point to same place.
package main
import (
"fmt"
)
func main() {
type student struct {
name string
age int
}
p1 := &student{"hongseok", 13} // this mean create a new student, but we want only address of student, not value
p2 := p1
(*p1).age = 15 // because p1 and p2 point to same memory (*p2).age also changed
fmt.Println("1.", p2.age) // 15
p2.age = 32 // in golang I could write (*p2).ago or p2.ago this is the same
fmt.Println("2.", p1.age) // 32
fmt.Println("3.",p1, "==", p2)
fmt.Printf("4. %p == %p\n", p1, p2)
// But now I force point p2 to new place
p2 = &student{"another student", 12}
fmt.Println("5.", p1, "!=", p2)
fmt.Printf("6. %p == %p\n", p1, p2)
p1.age = 14 // does it influce p2.age? no! Why? Because it is in different address
fmt.Println("7.", p1, "!=", p2)
// but could is somehow force that point to same address ? Of course
p2 = p1 // p2 will point to same place as p1 and old value of p2 will be freed by garbage collector
}
And don't be confused - pointer can also points named value.
a := 42 // means allocate memory for integer, and we give that memory name "a"
p := &a
*p++ // it change value of a
a = 5 // and of course this change value of *p
And now back to methods, that receiver is/is not a pointer. If receiver of method is pointer, that means you can change it value - the same way as I did few lines ago.
If method receiver is not a pointer, that means - before calling a method, it will be created a copy of struct and method will be called on that copy. You of course can change value of copy, but it does not influence original value.

What is the meaning of '*' and '&'?

I am doing the http://tour.golang.org/. Could anyone explain this function to me lines 1,3,5 and 7, especially what '*' and '&' do? By mentioning them in a function declaration, what are they supposed/expected to do? A toy example:
1: func intial1(var1 int, var2 int, func1.newfunc[]) *callproperfunction {
2:
3: addition:= make ([] add1, var1)
4: for i:=1;i<var2;i++ {
5: var2 [i] = *addtother (randomstring(lengthofcurrent))
6: }
7: return &callproperfunction {var1 int, var2 int, func1.newfunc[], jackpot}
8: }
It seems that they are pointers like what we have in C++. But I cannot connect those concepts to what we have here. In other words, what '*' an '&' do when I use them in function declaration in Go.
I know what reference and dereference mean. I cannot understand how we can use a pointer to a function in Go? For example lines 1 and 7, what do these two lines do? The function named intial1 is declared that returns a pointer? And in line 7, we call it with arguments using the return function.
This is possibly one of the most confusing things in Go. There are basically 3 cases you need to understand:
The & Operator
& goes in front of a variable when you want to get that variable's memory address.
The * Operator
* goes in front of a variable that holds a memory address and resolves it (it is therefore the counterpart to the & operator). It goes and gets the thing that the pointer was pointing at, e.g. *myString.
myString := "Hi"
fmt.Println(*&myString) // prints "Hi"
or more usefully, something like
myStructPointer = &myStruct
// ...
(*myStructPointer).someAttribute = "New Value"
* in front of a Type
When * is put in front of a type, e.g. *string, it becomes part of the type declaration, so you can say "this variable holds a pointer to a string". For example:
var str_pointer *string
So the confusing thing is that the * really gets used for 2 separate (albeit related) things. The star can be an operator or part of a type.
Your question doesn't match very well the example given but I'll try to be straightforward.
Let's suppose we have a variable named a which holds the integer 5 and another variable named p which is going to be a pointer.
This is where the * and & come into the game.
Printing variables with them can generate different output, so it all depends on the situation and how well you use.
The use of * and & can save you lines of code (that doesn't really matter in small projects) and make your code more beautiful/readable.
& returns the memory address of the following variable.
* returns the value of the following variable (which should hold the memory address of a variable, unless you want to get weird output and possibly problems because you're accessing your computer's RAM)
var a = 5
var p = &a // p holds variable a's memory address
fmt.Printf("Address of var a: %p\n", p)
fmt.Printf("Value of var a: %v\n", *p)
// Let's change a value (using the initial variable or the pointer)
*p = 3 // using pointer
a = 3 // using initial var
fmt.Printf("Address of var a: %p\n", p)
fmt.Printf("Value of var a: %v\n", *p)
All in all, when using * and & in remember that * is for setting the value of the variable you're pointing to and & is the address of the variable you're pointing to/want to point to.
Hope this answer helps.
Those are pointers like we have in C++.
The differences are:
Instead of -> to call a method on a pointer, you always use ., i.e. pointer.method().
There are no dangling pointers. It is perfectly valid to return a pointer to a local variable. Golang will ensure the lifetime of the object and garbage-collect it when it's no longer needed.
Pointers can be created with new() or by creating a object object{} and taking the address of it with &.
Golang does not allow pointer-arithmetic (arrays do not decay to pointers) and insecure casting. All downcasts will be checked using the runtime-type of the variable and either panic or return false as second return-value when the instance is of the wrong type, depending on whether you actually take the second return type or not.
This is by far the easiest way to understand all the three cases as explained in the #Everett answer
func zero(x int) {
x = 0
}
func main() {
x := 5
zero(x)
fmt.Println(x) // x is still 5
}
If you need a variable to be changed inside a function then pass the memory address as a parmeter and use the pointer of this memory address to change the variable permanently.
Observe the use of * in front of int in the example. Here it just represents the variable that is passed as a parameter is the address of type int.
func zero(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
zero(&x)
fmt.Println(x) // x is 0
}
Simple explanation.. its just like, you want to mutate the original value
func zero(num *int){ // add * to datatype
*num = 0 // can mutate the original number
}
i := 5
zero(&i) // passing variable with & will allows other function to mutate the current value of variable```
& Operator gets the memory address where as * Opeartor holds the memory address of particular variable.

Strange behaviour when passing a struct property (slice) to a function that removes elements from it

I've started learning Go these days and got stuck in trying to pass a struct property's value (a slice) to a function. Apparently it's being passed as a reference (or it holds a pointer to its slice) and changes made inside the function affect it.
Here is my code, in which testFunction is supposed to receive a slice, remove its first 3 elements and print the updated values, but without affecting it externally:
package main
import (
"fmt"
)
type testStruct struct {
testArray []float64
}
var test = testStruct {
testArray: []float64{10,20,30,40,50},
}
func main() {
fmt.Println(test.testArray)
testFunction(test.testArray)
fmt.Println(test.testArray)
}
func testFunction(array []float64) {
for i:=0; i<3; i++ {
array = removeFrom(array, 0)
}
fmt.Println(array)
}
func removeFrom(array []float64, index int) []float64 {
return append(array[:index], array[index+1:]...)
}
That outputs:
[10 20 30 40 50]
[40 50]
[40 50 50 50 50]
My question is: what is causing the third fmt.Println to print this strange result?
Playground: https://play.golang.org/p/G8W3H085In
p.s.: This code is only an example. It's not my goal to remove the first elements of something. I just wanna know what is causing this strange behaviour.
Usually we don't know whether a given call to append will cause a reallocation, so we can't assume that the original slice refers to the same array as the resulting slice, nor that it refers to a different one.
To use slices correctly, it's important to remember that although the elements of the underlying array are indirect, the slice's pointer, length and capacity are not.
As a result, it's usual to assign the result of a call to append to the same slice variable:
array = append(array, ...)
So to sum up, to receive the desired result always remember to assign the append function to a new or the same slice variable.
Here is the corrected and working code:
package main
import (
"fmt"
)
type testStruct struct {
testArray []float64
}
var test = testStruct {
testArray: []float64{10,20,30,40,50},
}
func main() {
fmt.Println(test.testArray)
a := testFunction(test.testArray)
fmt.Println(a)
}
func testFunction(array []float64)[]float64 {
for i:=0; i<3; i++ {
array = removeFrom(array, 0)
}
fmt.Println(array)
return array
}
func removeFrom(array []float64, index int) []float64 {
return append(array[:index], array[index+1:]...)
}
Check it the working code on Go Playground.
Another solution is to pass the array argument via pointer reference:
func testFunction(array *[]float64) {
for i:=0; i<3; i++ {
*array = removeFrom(*array, 0)
}
fmt.Println(*array)
}
Go Playground
The slice is a composite type. It has a pointer to the data, the length and the capacity. When you pass it as an argument you're passing those values, the pointer, the length and the capacity; they are copies, always.
In your case you modify the data within the slice when you call removeFrom(), which you can do because you've copied the value of a pointer to the original data into the func, but the length and capacity remain unchanged outside the scope of that function as those are not pointers.
So, when you print it again from main() you see the altered values but it still uses the original length and capacity as any changes made to those within the scope of the other funcs were actually on copies of those values.
Here is a useful blog post about slices https://blog.golang.org/slices. It states this in particular.
It's important to understand that even though a slice contains a
pointer, it is itself a value. Under the covers, it is a struct value
holding a pointer and a length. It is not a pointer to a struct.
The reason you see [40 50 50 50 50] is because you changed the values in the slice, but you did not alter the slice itself(it's cap and len)

Resources